From 01826412811cfd0a2e59a3b3a6e2a41b179a18d6 Mon Sep 17 00:00:00 2001 From: Sean Fausett Date: Mon, 29 Nov 2010 09:08:11 +1300 Subject: [PATCH] Merged machine settings into machine components. Added save state support to all machine components. Switched from xml serialization to binary serialization. Refactored audio service for performance. Bumped machine version to 0.9.0 for next release. Miscellaneous cosmetic or minor changes. --- Library/DispatcherExtensions.cs | 24 +- .../Jellyfish.Library.Silverlight.csproj | 6 - ...Jellyfish.Library.Silverlight.Phone.csproj | 7 +- .../Phone/Properties/AssemblyInfo.cs | 6 +- .../Silverlight/Properties/AssemblyInfo.cs | 6 +- Library/Wpf/Jellyfish.Library.Wpf.csproj | 4 - Library/Wpf/Properties/AssemblyInfo.cs | 6 +- Library/Xna/GameBase.cs | 7 + .../Xna/Jellyfish.Library.Xna.Phone.csproj | 10 - Library/Xna/Jellyfish.Library.Xna.Xbox.csproj | 10 - Library/Xna/Jellyfish.Library.Xna.csproj | 8 +- Library/Xna/Properties/AssemblyInfo.cs | 6 +- Virtu/Cpu.cs | 69 ++- Virtu/Disk525.cs | 29 ++ Virtu/DiskIIController.cs | 55 ++- Virtu/DiskIIDrive.cs | 48 ++- Virtu/GamePort.cs | 152 +++++-- Virtu/Keyboard.cs | 163 +++++-- Virtu/Machine.cs | 78 +++- Virtu/MachineComponent.cs | 13 +- Virtu/MachineEvents.cs | 2 +- Virtu/MachineSettings.cs | 408 ------------------ Virtu/Memory.cs | 85 +++- Virtu/NoSlotClock.cs | 83 ++-- Virtu/Services/AudioService.cs | 19 +- Virtu/Services/GamePortService.cs | 59 +-- Virtu/Services/IsolatedStorageService.cs | 8 +- Virtu/Services/MachineServices.cs | 4 +- Virtu/Services/StorageService.cs | 124 +++++- Virtu/Services/VideoService.cs | 8 +- .../Jellyfish.Virtu.Silverlight.csproj | 6 - Virtu/Silverlight/MainPage.xaml.cs | 14 +- .../Jellyfish.Virtu.Silverlight.Phone.csproj | 4 - Virtu/Silverlight/Phone/MainPage.xaml.cs | 10 +- .../Phone/Properties/AssemblyInfo.cs | 7 +- Virtu/Silverlight/Properties/AssemblyInfo.cs | 7 +- .../Services/SilverlightAudioService.cs | 7 +- .../Services/SilverlightDebugService.cs | 2 +- .../Services/SilverlightKeyboardService.cs | 9 +- .../Services/SilverlightVideoService.cs | 34 +- Virtu/Speaker.cs | 43 +- Virtu/Video.cs | 277 ++++++++---- Virtu/Wpf/Jellyfish.Virtu.Wpf.csproj | 4 - Virtu/Wpf/MainPage.xaml.cs | 23 +- Virtu/Wpf/Properties/AssemblyInfo.cs | 7 +- Virtu/Wpf/Services/WpfAudioService.cs | 5 +- Virtu/Wpf/Services/WpfDebugService.cs | 2 +- Virtu/Wpf/Services/WpfKeyboardService.cs | 6 +- Virtu/Wpf/Services/WpfVideoService.cs | 44 +- Virtu/Xna/Jellyfish.Virtu.Xna.Phone.csproj | 6 - Virtu/Xna/Jellyfish.Virtu.Xna.Xbox.csproj | 6 - Virtu/Xna/Jellyfish.Virtu.Xna.csproj | 6 - Virtu/Xna/Properties/AssemblyInfo.cs | 7 +- Virtu/Xna/Services/XnaAudioService.cs | 5 +- Virtu/Xna/Services/XnaGamePortService.cs | 33 +- Virtu/Xna/Services/XnaKeyboardService.cs | 6 +- Virtu/Xna/Services/XnaStorageService.cs | 8 +- Virtu/Xna/Services/XnaVideoService.cs | 18 +- 58 files changed, 1114 insertions(+), 999 deletions(-) delete mode 100644 Virtu/MachineSettings.cs diff --git a/Library/DispatcherExtensions.cs b/Library/DispatcherExtensions.cs index 645dc1c..0c3fdc0 100644 --- a/Library/DispatcherExtensions.cs +++ b/Library/DispatcherExtensions.cs @@ -5,7 +5,7 @@ namespace Jellyfish.Library { public static class DispatcherExtensions { - public static void CheckBeginInvoke(this Dispatcher dispatcher, Action action) + public static void Post(this Dispatcher dispatcher, Action action) { if (dispatcher == null) { @@ -16,18 +16,10 @@ public static void CheckBeginInvoke(this Dispatcher dispatcher, Action action) throw new ArgumentNullException("action"); } - if (dispatcher.CheckAccess()) - { - action(); - } - else - { - dispatcher.BeginInvoke(action); - } + new DispatcherSynchronizationContext(dispatcher).Post(state => action(), null); } -#if WINDOWS - public static void CheckInvoke(this Dispatcher dispatcher, Action action) + public static void Send(this Dispatcher dispatcher, Action action) { if (dispatcher == null) { @@ -38,15 +30,7 @@ public static void CheckInvoke(this Dispatcher dispatcher, Action action) throw new ArgumentNullException("action"); } - if (dispatcher.CheckAccess()) - { - action(); - } - else - { - dispatcher.Invoke(action); - } + new DispatcherSynchronizationContext(dispatcher).Send(state => action(), null); } -#endif } } diff --git a/Library/Silverlight/Jellyfish.Library.Silverlight.csproj b/Library/Silverlight/Jellyfish.Library.Silverlight.csproj index 2050bde..02ab22d 100644 --- a/Library/Silverlight/Jellyfish.Library.Silverlight.csproj +++ b/Library/Silverlight/Jellyfish.Library.Silverlight.csproj @@ -65,9 +65,6 @@ - - True - @@ -101,9 +98,6 @@ WaveFormat.cs - - XmlSerializerHelpers.cs - diff --git a/Library/Silverlight/Phone/Jellyfish.Library.Silverlight.Phone.csproj b/Library/Silverlight/Phone/Jellyfish.Library.Silverlight.Phone.csproj index cfc137b..e65f7dc 100644 --- a/Library/Silverlight/Phone/Jellyfish.Library.Silverlight.Phone.csproj +++ b/Library/Silverlight/Phone/Jellyfish.Library.Silverlight.Phone.csproj @@ -60,7 +60,6 @@ - @@ -75,6 +74,9 @@ IEnumerableExtensions.cs + + Lazy.cs + MathHelpers.cs @@ -90,9 +92,6 @@ WaveFormat.cs - - XmlSerializerHelpers.cs - ApplicationBase.cs diff --git a/Library/Silverlight/Phone/Properties/AssemblyInfo.cs b/Library/Silverlight/Phone/Properties/AssemblyInfo.cs index 9d84b33..02e6eca 100644 --- a/Library/Silverlight/Phone/Properties/AssemblyInfo.cs +++ b/Library/Silverlight/Phone/Properties/AssemblyInfo.cs @@ -11,9 +11,9 @@ [assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett")] -[assembly: AssemblyVersion("0.1.3.0")] -[assembly: AssemblyFileVersion("0.1.3.0")] -[assembly: AssemblyInformationalVersion("0.1.3.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] +[assembly: AssemblyInformationalVersion("0.2.0.0")] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Library/Silverlight/Properties/AssemblyInfo.cs b/Library/Silverlight/Properties/AssemblyInfo.cs index dfc4fb9..972e989 100644 --- a/Library/Silverlight/Properties/AssemblyInfo.cs +++ b/Library/Silverlight/Properties/AssemblyInfo.cs @@ -11,9 +11,9 @@ [assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett")] -[assembly: AssemblyVersion("0.1.3.0")] -[assembly: AssemblyFileVersion("0.1.3.0")] -[assembly: AssemblyInformationalVersion("0.1.3.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] +[assembly: AssemblyInformationalVersion("0.2.0.0")] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Library/Wpf/Jellyfish.Library.Wpf.csproj b/Library/Wpf/Jellyfish.Library.Wpf.csproj index b45dad7..01c4529 100644 --- a/Library/Wpf/Jellyfish.Library.Wpf.csproj +++ b/Library/Wpf/Jellyfish.Library.Wpf.csproj @@ -51,7 +51,6 @@ - @@ -107,9 +106,6 @@ WaveFormat.cs - - XmlSerializerHelpers.cs - diff --git a/Library/Wpf/Properties/AssemblyInfo.cs b/Library/Wpf/Properties/AssemblyInfo.cs index 55be616..0b8d668 100644 --- a/Library/Wpf/Properties/AssemblyInfo.cs +++ b/Library/Wpf/Properties/AssemblyInfo.cs @@ -11,9 +11,9 @@ [assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett")] -[assembly: AssemblyVersion("0.1.3.0")] -[assembly: AssemblyFileVersion("0.1.3.0")] -[assembly: AssemblyInformationalVersion("0.1.3.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] +[assembly: AssemblyInformationalVersion("0.2.0.0")] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Library/Xna/GameBase.cs b/Library/Xna/GameBase.cs index 6bfb2d4..c33147e 100644 --- a/Library/Xna/GameBase.cs +++ b/Library/Xna/GameBase.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Threading; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; @@ -21,9 +22,12 @@ public GameBase(string name) Content.RootDirectory = "Content"; GraphicsDeviceManager = new GraphicsDeviceManager(this); #if WINDOWS_PHONE + GraphicsDeviceManager.IsFullScreen = true; TargetElapsedTime = TimeSpan.FromTicks(333333); // 30 fps #elif XBOX Components.Add(new GamerServicesComponent(this)); +#else + SynchronizationContext = new System.Windows.Forms.WindowsFormsSynchronizationContext(); #endif GraphicsDeviceService = (IGraphicsDeviceService)Services.GetService(typeof(IGraphicsDeviceService)); @@ -48,5 +52,8 @@ protected override void Update(GameTime gameTime) public string Name { get; private set; } public GraphicsDeviceManager GraphicsDeviceManager { get; private set; } public IGraphicsDeviceService GraphicsDeviceService { get; private set; } +#if WINDOWS + public SynchronizationContext SynchronizationContext { get; private set; } +#endif } } diff --git a/Library/Xna/Jellyfish.Library.Xna.Phone.csproj b/Library/Xna/Jellyfish.Library.Xna.Phone.csproj index 39fb189..c577a79 100644 --- a/Library/Xna/Jellyfish.Library.Xna.Phone.csproj +++ b/Library/Xna/Jellyfish.Library.Xna.Phone.csproj @@ -83,13 +83,6 @@ False - - 4.0 - False - - - False - @@ -116,9 +109,6 @@ StringBuilderExtensions.cs - - XmlSerializerHelpers.cs - diff --git a/Library/Xna/Jellyfish.Library.Xna.Xbox.csproj b/Library/Xna/Jellyfish.Library.Xna.Xbox.csproj index d5157db..7e899d9 100644 --- a/Library/Xna/Jellyfish.Library.Xna.Xbox.csproj +++ b/Library/Xna/Jellyfish.Library.Xna.Xbox.csproj @@ -98,13 +98,6 @@ False - - 4.0 - False - - - False - @@ -131,9 +124,6 @@ StringBuilderExtensions.cs - - XmlSerializerHelpers.cs - diff --git a/Library/Xna/Jellyfish.Library.Xna.csproj b/Library/Xna/Jellyfish.Library.Xna.csproj index 289517a..692ba95 100644 --- a/Library/Xna/Jellyfish.Library.Xna.csproj +++ b/Library/Xna/Jellyfish.Library.Xna.csproj @@ -95,11 +95,10 @@ 4.0 False - + False - - 4.0 + False @@ -140,9 +139,6 @@ StringBuilderExtensions.cs - - XmlSerializerHelpers.cs - diff --git a/Library/Xna/Properties/AssemblyInfo.cs b/Library/Xna/Properties/AssemblyInfo.cs index 1257789..13881d3 100644 --- a/Library/Xna/Properties/AssemblyInfo.cs +++ b/Library/Xna/Properties/AssemblyInfo.cs @@ -17,9 +17,9 @@ [assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett")] -[assembly: AssemblyVersion("0.1.3.0")] -[assembly: AssemblyFileVersion("0.1.3.0")] -[assembly: AssemblyInformationalVersion("0.1.3.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] +[assembly: AssemblyInformationalVersion("0.2.0.0")] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Virtu/Cpu.cs b/Virtu/Cpu.cs index d926a1a..a2b9773 100644 --- a/Virtu/Cpu.cs +++ b/Virtu/Cpu.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.IO; namespace Jellyfish.Virtu { @@ -144,16 +145,17 @@ public Cpu(Machine machine) : Execute65X02SedF8, Execute65C02SbcF9, Execute65C02PlxFA, Execute65C02NopFB, Execute65C02NopFC, Execute65C02SbcFD, Execute65C02IncFE, Execute65C02NopFF }; - - RS = 0xFF; } public override void Initialize() { _memory = Machine.Memory; - UpdateSettings(); - Machine.Video.VSync += (sender, e) => UpdateSettings(); + Is65C02 = true; + IsThrottled = true; + Multiplier = 1; + + RS = 0xFF; } public override void Reset() @@ -161,15 +163,53 @@ public override void Reset() RS = (RS - 3) & 0xFF; // [4-14] RPC = _memory.ReadRomRegionE0FF(0xFFFC) | (_memory.ReadRomRegionE0FF(0xFFFD) << 8); RP |= (PB | PI); - if (Machine.Settings.Cpu.Is65C02) // [C-10] + if (Is65C02) // [C-10] { RP &= ~PD; } } + 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.CurrentCulture, "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}", + 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}", RA, RX, RY, RP, RS, RPC, EA, CC); } @@ -184,11 +224,6 @@ public int Execute() return CC; } - public void ToggleThrottle() - { - Machine.Settings.Cpu.IsThrottled ^= true; - } - #region Core Operand Actions private void GetAddressAbs() // abs { @@ -740,7 +775,7 @@ private void ExecuteIrq(int cc) Push(RPC & 0xFF); Push(RP & ~PB); RP |= PI; - if (Machine.Settings.Cpu.Is65C02) // [C-10] + if (Is65C02) // [C-10] { RP &= ~PD; } @@ -830,7 +865,7 @@ private void ExecuteNmi(int cc) Push(RPC & 0xFF); Push(RP & ~PB); RP |= PI; - if (Machine.Settings.Cpu.Is65C02) // [C-10] + if (Is65C02) // [C-10] { RP &= ~PD; } @@ -3203,10 +3238,9 @@ private void Execute65C02Tsb0C() // tsb abs } #endregion - private void UpdateSettings() - { - _executeOpCode = Machine.Settings.Cpu.Is65C02 ? ExecuteOpCode65C02 : ExecuteOpCode65N02; - } + public bool Is65C02 { get { return _is65C02; } set { _is65C02 = value; _executeOpCode = _is65C02 ? ExecuteOpCode65C02 : ExecuteOpCode65N02; } } + public bool IsThrottled { get; set; } + public int Multiplier { get; set; } public int RA { get; private set; } public int RX { get; private set; } @@ -3221,6 +3255,7 @@ private void UpdateSettings() private Memory _memory; + private bool _is65C02; private Action[] _executeOpCode; } } diff --git a/Virtu/Disk525.cs b/Virtu/Disk525.cs index 040a94d..4bcdb26 100644 --- a/Virtu/Disk525.cs +++ b/Virtu/Disk525.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; namespace Jellyfish.Virtu { @@ -35,6 +36,34 @@ public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected 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(); + bool isWriteProtected = reader.ReadBoolean(); + byte[] data = reader.ReadBytes(reader.ReadInt32()); + + return CreateDisk(name, data, isWriteProtected); + } + + public void SaveState(BinaryWriter writer) + { + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + + writer.Write(Name); + writer.Write(IsWriteProtected); + writer.Write(Data.Length); + writer.Write(Data); + } + public abstract void ReadTrack(int number, int fraction, byte[] buffer); public abstract void WriteTrack(int number, int fraction, byte[] buffer); diff --git a/Virtu/DiskIIController.cs b/Virtu/DiskIIController.cs index 4ee4476..dced1fa 100644 --- a/Virtu/DiskIIController.cs +++ b/Virtu/DiskIIController.cs @@ -1,7 +1,8 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; using Jellyfish.Library; using Jellyfish.Virtu.Services; -using Jellyfish.Virtu.Settings; namespace Jellyfish.Virtu { @@ -14,21 +15,8 @@ public DiskIIController(Machine machine) : public override void Initialize() { - var romStream = StorageService.GetResourceStream("Roms/DiskII.rom", 0x0100); - romStream.ReadBlock(_romRegionC1C7, 0x0000, 0x0100); - - _drives[0].InsertDisk("Default.dsk", StorageService.GetResourceStream("Disks/Default.dsk", 0x23000), false); -#if WINDOWS - var settings = Machine.Settings.DiskII; - if (settings.Disk1.Name.Length > 0) - { - _drives[0].InsertDisk(settings.Disk1.Name, settings.Disk1.IsWriteProtected); - } - if (settings.Disk2.Name.Length > 0) - { - _drives[1].InsertDisk(settings.Disk2.Name, settings.Disk2.IsWriteProtected); - } -#endif + StorageService.LoadResource("Roms/DiskII.rom", 0x0100, stream => stream.ReadBlock(_romRegionC1C7, 0, 0x0100)); + StorageService.LoadResource("Disks/Default.dsk", 0x23000, stream => _drives[0].InsertDisk("Default.dsk", stream, false)); } public override void Reset() @@ -40,9 +28,38 @@ public override void Reset() _writeMode = false; } - public override void Uninitialize() + public override void LoadState(BinaryReader reader, Version version) { - Flush(); + 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(); + _drives.ForEach(drive => drive.LoadState(reader, version)); + } + + 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); + _drives.ForEach(drive => drive.SaveState(writer)); } [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] diff --git a/Virtu/DiskIIDrive.cs b/Virtu/DiskIIDrive.cs index fc2249e..a9ae9db 100644 --- a/Virtu/DiskIIDrive.cs +++ b/Virtu/DiskIIDrive.cs @@ -1,7 +1,7 @@ using System; using System.IO; -using System.Security; using Jellyfish.Library; +using Jellyfish.Virtu.Services; namespace Jellyfish.Virtu { @@ -15,13 +15,49 @@ public DiskIIDrive() DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3 } - [SecurityCritical] + public 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); + } + _disk = reader.ReadBoolean() ? Disk525.LoadState(reader, version) : null; + } + + public 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) + { + _disk.SaveState(writer); + } + } + public void InsertDisk(string fileName, bool isWriteProtected) { - using (var stream = File.OpenRead(fileName)) - { - InsertDisk(fileName, stream, isWriteProtected); - } + StorageService.LoadFile(fileName, stream => InsertDisk(fileName, stream, isWriteProtected)); } public void InsertDisk(string name, Stream stream, bool isWriteProtected) diff --git a/Virtu/GamePort.cs b/Virtu/GamePort.cs index ff56aea..8d420a1 100644 --- a/Virtu/GamePort.cs +++ b/Virtu/GamePort.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; using Jellyfish.Library; using Jellyfish.Virtu.Services; @@ -20,30 +21,88 @@ public override void Initialize() { _keyboardService = Machine.Services.GetService(); _gamePortService = Machine.Services.GetService(); + + JoystickDeadZone = 0.4; + } + + public override void LoadState(BinaryReader reader, Version version) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + JoystickDeadZone = reader.ReadDouble(); + + 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(); + } + + public override void SaveState(BinaryWriter writer) + { + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + + 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); } public bool ReadButton0() { - var settings = Machine.Settings.GamePort; - return (_gamePortService.IsButton0Down || _keyboardService.IsOpenAppleKeyDown || - (settings.UseKeyboard && (settings.Key.Button0 > 0) && _keyboardService.IsKeyDown(settings.Key.Button0))); + (UseKeyboard && (Button0Key > 0) && _keyboardService.IsKeyDown(Button0Key))); } public bool ReadButton1() { - var settings = Machine.Settings.GamePort; - return (_gamePortService.IsButton1Down || _keyboardService.IsCloseAppleKeyDown || - (settings.UseKeyboard && (settings.Key.Button1 > 0) && _keyboardService.IsKeyDown(settings.Key.Button1))); + (UseKeyboard && (Button1Key > 0) && _keyboardService.IsKeyDown(Button1Key))); } public bool ReadButton2() { - var settings = Machine.Settings.GamePort; - return (_gamePortService.IsButton2Down || !_keyboardService.IsShiftKeyDown || // Shift' [TN9] - (settings.UseKeyboard && (settings.Key.Button2 > 0) && _keyboardService.IsKeyDown(settings.Key.Button2))); + (UseKeyboard && (Button2Key > 0) && _keyboardService.IsKeyDown(Button2Key))); } [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] @@ -54,55 +113,53 @@ public void TriggerTimers() int paddle2 = _gamePortService.Paddle2; int paddle3 = _gamePortService.Paddle3; - var settings = Machine.Settings.GamePort; - - if (settings.UseKeyboard) // override + if (UseKeyboard) // override { - if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) || - ((settings.Key.Joystick0.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Left)) || - ((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft))) + if (((Joystick0UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0UpLeftKey)) || + ((Joystick0LeftKey > 0) && _keyboardService.IsKeyDown(Joystick0LeftKey)) || + ((Joystick0DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0DownLeftKey))) { paddle0 -= 128; } - if (((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)) || - ((settings.Key.Joystick0.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Right)) || - ((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight))) + if (((Joystick0UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick0UpRightKey)) || + ((Joystick0RightKey > 0) && _keyboardService.IsKeyDown(Joystick0RightKey)) || + ((Joystick0DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick0DownRightKey))) { paddle0 += 128; } - if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) || - ((settings.Key.Joystick0.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Up)) || - ((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight))) + if (((Joystick0UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0UpLeftKey)) || + ((Joystick0UpKey > 0) && _keyboardService.IsKeyDown(Joystick0UpKey)) || + ((Joystick0UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick0UpRightKey))) { paddle1 -= 128; } - if (((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)) || - ((settings.Key.Joystick0.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Down)) || - ((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight))) + if (((Joystick0DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0DownLeftKey)) || + ((Joystick0DownKey > 0) && _keyboardService.IsKeyDown(Joystick0DownKey)) || + ((Joystick0DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick0DownRightKey))) { paddle1 += 128; } - if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) || - ((settings.Key.Joystick1.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Left)) || - ((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft))) + if (((Joystick1UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1UpLeftKey)) || + ((Joystick1LeftKey > 0) && _keyboardService.IsKeyDown(Joystick1LeftKey)) || + ((Joystick1DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1DownLeftKey))) { paddle2 -= 128; } - if (((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)) || - ((settings.Key.Joystick1.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Right)) || - ((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight))) + if (((Joystick1UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick1UpRightKey)) || + ((Joystick1RightKey > 0) && _keyboardService.IsKeyDown(Joystick1RightKey)) || + ((Joystick1DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick1DownRightKey))) { paddle2 += 128; } - if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) || - ((settings.Key.Joystick1.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Up)) || - ((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight))) + if (((Joystick1UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1UpLeftKey)) || + ((Joystick1UpKey > 0) && _keyboardService.IsKeyDown(Joystick1UpKey)) || + ((Joystick1UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick1UpRightKey))) { paddle3 -= 128; } - if (((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)) || - ((settings.Key.Joystick1.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Down)) || - ((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight))) + if (((Joystick1DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1DownLeftKey)) || + ((Joystick1DownKey > 0) && _keyboardService.IsKeyDown(Joystick1DownKey)) || + ((Joystick1DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick1DownRightKey))) { paddle3 += 128; } @@ -139,6 +196,29 @@ private void ResetPaddle3StrobeEvent() Paddle3Strobe = false; } + public double JoystickDeadZone { get; set; } + + public bool UseKeyboard { 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 int Button0Key { get; set; } + public int Button1Key { get; set; } + public int Button2Key { get; set; } + public bool Paddle0Strobe { get; private set; } public bool Paddle1Strobe { get; private set; } public bool Paddle2Strobe { get; private set; } diff --git a/Virtu/Keyboard.cs b/Virtu/Keyboard.cs index a1b4663..a839f32 100644 --- a/Virtu/Keyboard.cs +++ b/Virtu/Keyboard.cs @@ -1,4 +1,6 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; using Jellyfish.Virtu.Services; namespace Jellyfish.Virtu @@ -16,6 +18,64 @@ public override void Initialize() _gamePortService = Machine.Services.GetService(); } + public override void LoadState(BinaryReader reader, Version version) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + 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.ReadInt32(); + Button1Key = reader.ReadInt32(); + Button2Key = reader.ReadInt32(); + } + + public override void SaveState(BinaryWriter writer) + { + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + + 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); + } + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] public int ReadLatch() { @@ -24,87 +84,85 @@ public int ReadLatch() return Latch; } - var settings = Machine.Settings.Keyboard; - - if (settings.UseGamePort) + if (UseGamePort) { - if ((settings.Key.Joystick0.UpLeft > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsLeft) + if ((Joystick0UpLeftKey > 0) && _gamePortService.IsJoystick0Up && _gamePortService.IsJoystick0Left) { - Latch = settings.Key.Joystick0.UpLeft; + Latch = Joystick0UpLeftKey; } - else if ((settings.Key.Joystick0.UpRight > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsRight) + else if ((Joystick0UpRightKey > 0) && _gamePortService.IsJoystick0Up && _gamePortService.IsJoystick0Right) { - Latch = settings.Key.Joystick0.UpRight; + Latch = Joystick0UpRightKey; } - else if ((settings.Key.Joystick0.DownLeft > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsLeft) + else if ((Joystick0DownLeftKey > 0) && _gamePortService.IsJoystick0Down && _gamePortService.IsJoystick0Left) { - Latch = settings.Key.Joystick0.DownLeft; + Latch = Joystick0DownLeftKey; } - else if ((settings.Key.Joystick0.DownRight > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsRight) + else if ((Joystick0DownRightKey > 0) && _gamePortService.IsJoystick0Down && _gamePortService.IsJoystick0Right) { - Latch = settings.Key.Joystick0.DownRight; + Latch = Joystick0DownRightKey; } - else if ((settings.Key.Joystick0.Up > 0) && _gamePortService.Joystick0.IsUp) + else if ((Joystick0UpKey > 0) && _gamePortService.IsJoystick0Up) { - Latch = settings.Key.Joystick0.Up; + Latch = Joystick0UpKey; } - else if ((settings.Key.Joystick0.Left > 0) && _gamePortService.Joystick0.IsLeft) + else if ((Joystick0LeftKey > 0) && _gamePortService.IsJoystick0Left) { - Latch = settings.Key.Joystick0.Left; + Latch = Joystick0LeftKey; } - else if ((settings.Key.Joystick0.Right > 0) && _gamePortService.Joystick0.IsRight) + else if ((Joystick0RightKey > 0) && _gamePortService.IsJoystick0Right) { - Latch = settings.Key.Joystick0.Right; + Latch = Joystick0RightKey; } - else if ((settings.Key.Joystick0.Down > 0) && _gamePortService.Joystick0.IsDown) + else if ((Joystick0DownKey > 0) && _gamePortService.IsJoystick0Down) { - Latch = settings.Key.Joystick0.Down; + Latch = Joystick0DownKey; } - if ((settings.Key.Joystick1.UpLeft > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsLeft) // override + if ((Joystick1UpLeftKey > 0) && _gamePortService.IsJoystick1Up && _gamePortService.IsJoystick1Left) // override { - Latch = settings.Key.Joystick1.UpLeft; + Latch = Joystick1UpLeftKey; } - else if ((settings.Key.Joystick1.UpRight > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsRight) + else if ((Joystick1UpRightKey > 0) && _gamePortService.IsJoystick1Up && _gamePortService.IsJoystick1Right) { - Latch = settings.Key.Joystick1.UpRight; + Latch = Joystick1UpRightKey; } - else if ((settings.Key.Joystick1.DownLeft > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsLeft) + else if ((Joystick1DownLeftKey > 0) && _gamePortService.IsJoystick1Down && _gamePortService.IsJoystick1Left) { - Latch = settings.Key.Joystick1.DownLeft; + Latch = Joystick1DownLeftKey; } - else if ((settings.Key.Joystick1.DownRight > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsRight) + else if ((Joystick1DownRightKey > 0) && _gamePortService.IsJoystick1Down && _gamePortService.IsJoystick1Right) { - Latch = settings.Key.Joystick1.DownRight; + Latch = Joystick1DownRightKey; } - else if ((settings.Key.Joystick1.Up > 0) && _gamePortService.Joystick1.IsUp) + else if ((Joystick1UpKey > 0) && _gamePortService.IsJoystick1Up) { - Latch = settings.Key.Joystick1.Up; + Latch = Joystick1UpKey; } - else if ((settings.Key.Joystick1.Left > 0) && _gamePortService.Joystick1.IsLeft) + else if ((Joystick1LeftKey > 0) && _gamePortService.IsJoystick1Left) { - Latch = settings.Key.Joystick1.Left; + Latch = Joystick1LeftKey; } - else if ((settings.Key.Joystick1.Right > 0) && _gamePortService.Joystick1.IsRight) + else if ((Joystick1RightKey > 0) && _gamePortService.IsJoystick1Right) { - Latch = settings.Key.Joystick1.Right; + Latch = Joystick1RightKey; } - else if ((settings.Key.Joystick1.Down > 0) && _gamePortService.Joystick1.IsDown) + else if ((Joystick1DownKey > 0) && _gamePortService.IsJoystick1Down) { - Latch = settings.Key.Joystick1.Down; + Latch = Joystick1DownKey; } - if ((settings.Key.Button0 > 0) && _gamePortService.IsButton0Down) // override + if ((Button0Key > 0) && _gamePortService.IsButton0Down) // override { - Latch = settings.Key.Button0; + Latch = Button0Key; } - else if ((settings.Key.Button1 > 0) && _gamePortService.IsButton1Down) + else if ((Button1Key > 0) && _gamePortService.IsButton1Down) { - Latch = settings.Key.Button1; + Latch = Button1Key; } - else if ((settings.Key.Button2 > 0) && _gamePortService.IsButton2Down) + else if ((Button2Key > 0) && _gamePortService.IsButton2Down) { - Latch = settings.Key.Button2; + Latch = Button2Key; } } @@ -116,6 +174,27 @@ public void ResetStrobe() Strobe = false; } + 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 int Button0Key { get; set; } + public int Button1Key { get; set; } + public int Button2Key { get; set; } + public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } } public int Latch { get { return _latch; } set { _latch = value; Strobe = true; } } public bool Strobe { get; private set; } diff --git a/Virtu/Machine.cs b/Virtu/Machine.cs index e6a6c18..a8e4557 100644 --- a/Virtu/Machine.cs +++ b/Virtu/Machine.cs @@ -1,9 +1,11 @@ using System; using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Threading; using Jellyfish.Library; using Jellyfish.Virtu.Services; -using Jellyfish.Virtu.Settings; namespace Jellyfish.Virtu { @@ -15,7 +17,6 @@ public Machine() { Events = new MachineEvents(); Services = new MachineServices(); - Settings = new MachineSettings(); Cpu = new Cpu(this); Memory = new Memory(this); @@ -36,7 +37,7 @@ public Machine() Slot7 = emptySlot; Slots = new Collection { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; - Components = new Collection { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, 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 }; Thread = new Thread(Run) { Name = "Machine" }; } @@ -49,14 +50,11 @@ public void Dispose() public void Reset() { - Components.ForEach(component => component.Reset()); // while machine starting or paused + Components.ForEach(component => component.Reset()); } public void Start() { - _storageService = Services.GetService(); - _storageService.Load(MachineSettings.FileName, stream => Settings.Deserialize(stream)); - State = MachineState.Starting; Thread.Start(); } @@ -83,11 +81,6 @@ public void Stop() Thread.Join(); } State = MachineState.Stopped; - - if (_storageService != null) - { - _storageService.Save(MachineSettings.FileName, stream => Settings.Serialize(stream)); - } } public DiskIIController FindDiskIIController() @@ -104,10 +97,59 @@ public DiskIIController FindDiskIIController() return null; } - private void Run() // machine thread + private void Initialize() { Components.ForEach(component => component.Initialize()); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void LoadState() + { + var storageService = Services.GetService(); + storageService.Load(Machine.LastStateFileName, stream => + { + try + { + var version = new Version(Version); + using (var reader = new BinaryReader(stream)) + { + version = new Version(reader.ReadString()); + Components.ForEach(component => component.LoadState(reader, version)); + } + } + catch (Exception) + { + if (Debugger.IsAttached) + { + Debugger.Break(); + } + } + }); + } + + private void Uninitialize() + { + Components.ForEach(component => component.Uninitialize()); + } + + private void SaveState() + { + var storageService = Services.GetService(); + storageService.Save(Machine.LastStateFileName, stream => + { + using (var writer = new BinaryWriter(stream)) + { + writer.Write(Version); + Components.ForEach(component => component.SaveState(writer)); + } + }); + } + + private void Run() // machine thread + { + Initialize(); Reset(); + LoadState(); State = MachineState.Running; do @@ -126,12 +168,14 @@ private void Run() // machine thread } while (State != MachineState.Stopping); - Components.ForEach(component => component.Uninitialize()); + SaveState(); + Uninitialize(); } + public const string Version = "0.9.0.0"; + public MachineEvents Events { get; private set; } public MachineServices Services { get; private set; } - public MachineSettings Settings { get; private set; } public MachineState State { get; private set; } public Cpu Cpu { get; private set; } @@ -156,9 +200,9 @@ private void Run() // machine thread public Thread Thread { get; private set; } + private const string LastStateFileName = "LastState.bin"; + private AutoResetEvent _pauseEvent = new AutoResetEvent(false); private AutoResetEvent _unpauseEvent = new AutoResetEvent(false); - - private StorageService _storageService; } } diff --git a/Virtu/MachineComponent.cs b/Virtu/MachineComponent.cs index 44e1078..e1e3836 100644 --- a/Virtu/MachineComponent.cs +++ b/Virtu/MachineComponent.cs @@ -1,4 +1,7 @@ -namespace Jellyfish.Virtu +using System; +using System.IO; + +namespace Jellyfish.Virtu { public abstract class MachineComponent { @@ -15,10 +18,18 @@ public virtual void Reset() { } + public virtual void LoadState(BinaryReader reader, Version version) + { + } + public virtual void Uninitialize() { } + public virtual void SaveState(BinaryWriter writer) + { + } + protected Machine Machine { get; private set; } } } diff --git a/Virtu/MachineEvents.cs b/Virtu/MachineEvents.cs index a6013ef..f008d04 100644 --- a/Virtu/MachineEvents.cs +++ b/Virtu/MachineEvents.cs @@ -14,7 +14,7 @@ public MachineEvent(int delta, Action action) public override string ToString() { - return string.Format(CultureInfo.CurrentCulture, "Delta = {0} Action = {{{1}.{2}}}", Delta, Action.Method.DeclaringType.Name, Action.Method.Name); + return string.Format(CultureInfo.InvariantCulture, "Delta = {0} Action = {{{1}.{2}}}", Delta, Action.Method.DeclaringType.Name, Action.Method.Name); } public int Delta { get; set; } diff --git a/Virtu/MachineSettings.cs b/Virtu/MachineSettings.cs deleted file mode 100644 index d4314fd..0000000 --- a/Virtu/MachineSettings.cs +++ /dev/null @@ -1,408 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Xml; -using System.Xml.Linq; - -namespace Jellyfish.Virtu.Settings -{ - public sealed class MachineSettings - { - public MachineSettings() - { - Cpu = new CpuSettings { Is65C02 = true, IsThrottled = true, Multiplier = 1 }; - DiskII = new DiskIISettings - { - Disk1 = new DiskSettings { Name = string.Empty, IsWriteProtected = false }, - Disk2 = new DiskSettings { Name = string.Empty, IsWriteProtected = false } - }; - Keyboard = new KeyboardSettings - { - UseGamePort = false, - Key = new KeySettings - { - Joystick0 = new JoystickSettings { UpLeft = 0, Up = 'I', UpRight = 0, Left = 'J', Right = 'L', DownLeft = 0, Down = 'K', DownRight = 0 }, - Joystick1 = new JoystickSettings { UpLeft = 0, Up = 'E', UpRight = 0, Left = 'S', Right = 'F', DownLeft = 0, Down = 'D', DownRight = 0 }, - Button0 = 0, Button1 = 0, Button2 = 0 - } - }; - GamePort = new GamePortSettings - { - UseKeyboard = false, - Key = new KeySettings - { - Joystick0 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 }, - Joystick1 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 }, - Button0 = 0, Button1 = 0, Button2 = 0 - } - }; - Audio = new AudioSettings { Volume = 0.5 }; - Video = new VideoSettings - { - IsFullScreen = false, IsMonochrome = false, ScannerOptions = ScannerOptions.None, - Color = new ColorSettings - { - Black = 0xFF000000, // BGRA - DarkBlue = 0xFF000099, - DarkGreen = 0xFF117722, - MediumBlue = 0xFF0000FF, - Brown = 0xFF885500, - LightGrey = 0xFF99AAAA, - Green = 0xFF00EE11, - Aquamarine = 0xFF55FFAA, - DeepRed = 0xFFFF1111, - Purple = 0xFFDD00DD, - DarkGrey = 0xFF445555, - LightBlue = 0xFF33AAFF, - Orange = 0xFFFF4411, - Pink = 0xFFFF9988, - Yellow = 0xFFFFFF11, - White = 0xFFFFFFFF, - Monochrome = 0xFF00AA00 - } - }; - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public void Deserialize(Stream stream) - { - try - { - using (var reader = XmlReader.Create(stream)) - { - var ns = Namespace; - var root = XElement.Load(reader); - var cpu = root.Element(ns + "Cpu"); - Cpu = new CpuSettings - { - Is65C02 = (bool)cpu.Attribute("Is65C02"), - IsThrottled = (bool)cpu.Attribute("IsThrottled"), - Multiplier = (int)cpu.Attribute("Multiplier") - }; - var diskII = root.Element(ns + "DiskII"); - var disk1 = diskII.Element(ns + "Disk1"); - var disk2 = diskII.Element(ns + "Disk2"); - DiskII = new DiskIISettings - { - Disk1 = new DiskSettings - { - Name = (string)disk1.Attribute("Name") ?? string.Empty, - IsWriteProtected = (bool)disk1.Attribute("IsWriteProtected") - }, - Disk2 = new DiskSettings - { - Name = (string)disk2.Attribute("Name") ?? string.Empty, - IsWriteProtected = (bool)disk2.Attribute("IsWriteProtected") - }, - }; - var keyboard = root.Element(ns + "Keyboard"); - var key = keyboard.Element(ns + "Key"); - var joystick0 = key.Element(ns + "Joystick0"); - var joystick1 = key.Element(ns + "Joystick1"); - var buttons = key.Element(ns + "Buttons"); - Keyboard = new KeyboardSettings - { - UseGamePort = (bool)keyboard.Attribute("UseGamePort"), - Key = new KeySettings - { - Joystick0 = new JoystickSettings - { - UpLeft = (int)joystick0.Attribute("UpLeft"), - Up = (int)joystick0.Attribute("Up"), - UpRight = (int)joystick0.Attribute("UpRight"), - Left = (int)joystick0.Attribute("Left"), - Right = (int)joystick0.Attribute("Right"), - DownLeft = (int)joystick0.Attribute("DownLeft"), - Down = (int)joystick0.Attribute("Down"), - DownRight = (int)joystick0.Attribute("DownRight") - }, - Joystick1 = new JoystickSettings - { - UpLeft = (int)joystick1.Attribute("UpLeft"), - Up = (int)joystick1.Attribute("Up"), - UpRight = (int)joystick1.Attribute("UpRight"), - Left = (int)joystick1.Attribute("Left"), - Right = (int)joystick1.Attribute("Right"), - DownLeft = (int)joystick1.Attribute("DownLeft"), - Down = (int)joystick1.Attribute("Down"), - DownRight = (int)joystick1.Attribute("DownRight") - }, - Button0 = (int)buttons.Attribute("Button0"), - Button1 = (int)buttons.Attribute("Button1"), - Button2 = (int)buttons.Attribute("Button2") - } - }; - var gamePort = root.Element(ns + "GamePort"); - key = gamePort.Element(ns + "Key"); - joystick0 = key.Element(ns + "Joystick0"); - joystick1 = key.Element(ns + "Joystick1"); - buttons = key.Element(ns + "Buttons"); - GamePort = new GamePortSettings - { - UseKeyboard = (bool)gamePort.Attribute("UseKeyboard"), - Key = new KeySettings - { - Joystick0 = new JoystickSettings - { - UpLeft = (int)joystick0.Attribute("UpLeft"), - Up = (int)joystick0.Attribute("Up"), - UpRight = (int)joystick0.Attribute("UpRight"), - Left = (int)joystick0.Attribute("Left"), - Right = (int)joystick0.Attribute("Right"), - DownLeft = (int)joystick0.Attribute("DownLeft"), - Down = (int)joystick0.Attribute("Down"), - DownRight = (int)joystick0.Attribute("DownRight") - }, - Joystick1 = new JoystickSettings - { - UpLeft = (int)joystick1.Attribute("UpLeft"), - Up = (int)joystick1.Attribute("Up"), - UpRight = (int)joystick1.Attribute("UpRight"), - Left = (int)joystick1.Attribute("Left"), - Right = (int)joystick1.Attribute("Right"), - DownLeft = (int)joystick1.Attribute("DownLeft"), - Down = (int)joystick1.Attribute("Down"), - DownRight = (int)joystick1.Attribute("DownRight") - }, - Button0 = (int)buttons.Attribute("Button0"), - Button1 = (int)buttons.Attribute("Button1"), - Button2 = (int)buttons.Attribute("Button2") - } - }; - var audio = root.Element(ns + "Audio"); - Audio = new AudioSettings - { - Volume = (double)audio.Attribute("Volume") - }; - var video = root.Element(ns + "Video"); - var color = video.Element(ns + "Color"); - Video = new VideoSettings - { - IsFullScreen = (bool)video.Attribute("IsFullScreen"), - IsMonochrome = (bool)video.Attribute("IsMonochrome"), - ScannerOptions = (ScannerOptions)Enum.Parse(typeof(ScannerOptions), (string)video.Attribute("ScannerOptions"), true), - Color = new ColorSettings - { - Black = (uint)color.Attribute("Black"), - DarkBlue = (uint)color.Attribute("DarkBlue"), - DarkGreen = (uint)color.Attribute("DarkGreen"), - MediumBlue = (uint)color.Attribute("MediumBlue"), - Brown = (uint)color.Attribute("Brown"), - LightGrey = (uint)color.Attribute("LightGrey"), - Green = (uint)color.Attribute("Green"), - Aquamarine = (uint)color.Attribute("Aquamarine"), - DeepRed = (uint)color.Attribute("DeepRed"), - Purple = (uint)color.Attribute("Purple"), - DarkGrey = (uint)color.Attribute("DarkGrey"), - LightBlue = (uint)color.Attribute("LightBlue"), - Orange = (uint)color.Attribute("Orange"), - Pink = (uint)color.Attribute("Pink"), - Yellow = (uint)color.Attribute("Yellow"), - White = (uint)color.Attribute("White"), - Monochrome = (uint)color.Attribute("Monochrome") - } - }; - } - } - catch (Exception) - { - } - } - - public void Serialize(Stream stream) - { - var ns = Namespace; - var xml = new XElement(ns + "MachineSettings", - new XElement(ns + "Cpu", - new XAttribute("Is65C02", Cpu.Is65C02), - new XAttribute("IsThrottled", Cpu.IsThrottled), - new XAttribute("Multiplier", Cpu.Multiplier)), - new XElement(ns + "DiskII", - new XElement(ns + "Disk1", - new XAttribute("Name", DiskII.Disk1.Name), - new XAttribute("IsWriteProtected", DiskII.Disk1.IsWriteProtected)), - new XElement(ns + "Disk2", - new XAttribute("Name", DiskII.Disk2.Name), - new XAttribute("IsWriteProtected", DiskII.Disk2.IsWriteProtected))), - new XElement(ns + "Keyboard", - new XAttribute("UseGamePort", Keyboard.UseGamePort), - new XElement(ns + "Key", - new XElement(ns + "Joystick0", - new XAttribute("UpLeft", Keyboard.Key.Joystick0.UpLeft), - new XAttribute("Up", Keyboard.Key.Joystick0.Up), - new XAttribute("UpRight", Keyboard.Key.Joystick0.UpRight), - new XAttribute("Left", Keyboard.Key.Joystick0.Left), - new XAttribute("Right", Keyboard.Key.Joystick0.Right), - new XAttribute("DownLeft", Keyboard.Key.Joystick0.DownLeft), - new XAttribute("Down", Keyboard.Key.Joystick0.Down), - new XAttribute("DownRight", Keyboard.Key.Joystick0.DownRight)), - new XElement(ns + "Joystick1", - new XAttribute("UpLeft", Keyboard.Key.Joystick1.UpLeft), - new XAttribute("Up", Keyboard.Key.Joystick1.Up), - new XAttribute("UpRight", Keyboard.Key.Joystick1.UpRight), - new XAttribute("Left", Keyboard.Key.Joystick1.Left), - new XAttribute("Right", Keyboard.Key.Joystick1.Right), - new XAttribute("DownLeft", Keyboard.Key.Joystick1.DownLeft), - new XAttribute("Down", Keyboard.Key.Joystick1.Down), - new XAttribute("DownRight", Keyboard.Key.Joystick1.DownRight)), - new XElement(ns + "Buttons", - new XAttribute("Button0", Keyboard.Key.Button0), - new XAttribute("Button1", Keyboard.Key.Button1), - new XAttribute("Button2", Keyboard.Key.Button2)))), - new XElement(ns + "GamePort", - new XAttribute("UseKeyboard", GamePort.UseKeyboard), - new XElement(ns + "Key", - new XElement(ns + "Joystick0", - new XAttribute("UpLeft", GamePort.Key.Joystick0.UpLeft), - new XAttribute("Up", GamePort.Key.Joystick0.Up), - new XAttribute("UpRight", GamePort.Key.Joystick0.UpRight), - new XAttribute("Left", GamePort.Key.Joystick0.Left), - new XAttribute("Right", GamePort.Key.Joystick0.Right), - new XAttribute("DownLeft", GamePort.Key.Joystick0.DownLeft), - new XAttribute("Down", GamePort.Key.Joystick0.Down), - new XAttribute("DownRight", GamePort.Key.Joystick0.DownRight)), - new XElement(ns + "Joystick1", - new XAttribute("UpLeft", GamePort.Key.Joystick1.UpLeft), - new XAttribute("Up", GamePort.Key.Joystick1.Up), - new XAttribute("UpRight", GamePort.Key.Joystick1.UpRight), - new XAttribute("Left", GamePort.Key.Joystick1.Left), - new XAttribute("Right", GamePort.Key.Joystick1.Right), - new XAttribute("DownLeft", GamePort.Key.Joystick1.DownLeft), - new XAttribute("Down", GamePort.Key.Joystick1.Down), - new XAttribute("DownRight", GamePort.Key.Joystick1.DownRight)), - new XElement(ns + "Buttons", - new XAttribute("Button0", Keyboard.Key.Button0), - new XAttribute("Button1", Keyboard.Key.Button1), - new XAttribute("Button2", Keyboard.Key.Button2)))), - new XElement(ns + "Audio", - new XAttribute("Volume", Audio.Volume)), - new XElement(ns + "Video", - new XAttribute("IsFullScreen", Video.IsFullScreen), - new XAttribute("IsMonochrome", Video.IsMonochrome), - new XAttribute("ScannerOptions", Video.ScannerOptions), - new XElement(ns + "Color", - new XAttribute("Black", Video.Color.Black), - new XAttribute("DarkBlue", Video.Color.DarkBlue), - new XAttribute("DarkGreen", Video.Color.DarkGreen), - new XAttribute("MediumBlue", Video.Color.MediumBlue), - new XAttribute("Brown", Video.Color.Brown), - new XAttribute("LightGrey", Video.Color.LightGrey), - new XAttribute("Green", Video.Color.Green), - new XAttribute("Aquamarine", Video.Color.Aquamarine), - new XAttribute("DeepRed", Video.Color.DeepRed), - new XAttribute("Purple", Video.Color.Purple), - new XAttribute("DarkGrey", Video.Color.DarkGrey), - new XAttribute("LightBlue", Video.Color.LightBlue), - new XAttribute("Orange", Video.Color.Orange), - new XAttribute("Pink", Video.Color.Pink), - new XAttribute("Yellow", Video.Color.Yellow), - new XAttribute("White", Video.Color.White), - new XAttribute("Monochrome", Video.Color.Monochrome)))); - - using (var writer = XmlWriter.Create(stream)) - { - xml.WriteTo(writer); - } - } - - public CpuSettings Cpu { get; set; } - public DiskIISettings DiskII { get; set; } - public KeyboardSettings Keyboard { get; set; } - public GamePortSettings GamePort { get; set; } - public AudioSettings Audio { get; set; } - public VideoSettings Video { get; set; } - - public const string FileName = "Settings.xml"; - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly XNamespace Namespace = "http://schemas.jellyfish.co.nz/virtu/settings"; - } - - public sealed class CpuSettings - { - public bool Is65C02 { get; set; } - public bool IsThrottled { get; set; } - public int Multiplier { get; set; } - } - - public sealed class DiskSettings - { - public string Name { get; set; } - public bool IsWriteProtected { get; set; } - }; - - public sealed class DiskIISettings - { - public DiskSettings Disk1 { get; set; } - public DiskSettings Disk2 { get; set; } - }; - - public sealed class JoystickSettings - { - public int UpLeft { get; set; } - public int Up { get; set; } - public int UpRight { get; set; } - public int Left { get; set; } - public int Right { get; set; } - public int DownLeft { get; set; } - public int Down { get; set; } - public int DownRight { get; set; } - }; - - public sealed class KeySettings - { - public JoystickSettings Joystick0 { get; set; } - public JoystickSettings Joystick1 { get; set; } - public int Button0 { get; set; } - public int Button1 { get; set; } - public int Button2 { get; set; } - }; - - public sealed class KeyboardSettings - { - public bool UseGamePort { get; set; } - public KeySettings Key { get; set; } - } - - public sealed class GamePortSettings - { - public bool UseKeyboard { get; set; } - public KeySettings Key { get; set; } - } - - public sealed class AudioSettings - { - public double Volume { get; set; } - }; - - public sealed class ColorSettings - { - public uint Black { get; set; } - public uint DarkBlue { get; set; } - public uint DarkGreen { get; set; } - public uint MediumBlue { get; set; } - public uint Brown { get; set; } - public uint LightGrey { get; set; } - public uint Green { get; set; } - public uint Aquamarine { get; set; } - public uint DeepRed { get; set; } - public uint Purple { get; set; } - public uint DarkGrey { get; set; } - public uint LightBlue { get; set; } - public uint Orange { get; set; } - public uint Pink { get; set; } - public uint Yellow { get; set; } - public uint White { get; set; } - public uint Monochrome { get; set; } - } - - [Flags] - public enum ScannerOptions { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc - - public sealed class VideoSettings - { - public bool IsFullScreen { get; set; } - public bool IsMonochrome { get; set; } - public ScannerOptions ScannerOptions { get; set; } - public ColorSettings Color { get; set; } - }; -} diff --git a/Virtu/Memory.cs b/Virtu/Memory.cs index 8417e6a..3e675cb 100644 --- a/Virtu/Memory.cs +++ b/Virtu/Memory.cs @@ -77,6 +77,12 @@ public Memory(Machine machine) : WriteRamModeBankRegion[Video.ModeF][BankAux][Region080B] = WriteRamModeFAuxRegion080B; WriteRamModeBankRegion[Video.ModeF][BankAux][Region203F] = WriteRamModeFAuxRegion203F; WriteRamModeBankRegion[Video.ModeF][BankAux][Region405F] = WriteRamModeFAuxRegion405F; + + _writeIoRegionC0C0 = WriteIoRegionC0C0; // cache delegates; avoids garbage + _writeIoRegionC1C7 = WriteIoRegionC1C7; + _writeIoRegionC3C3 = WriteIoRegionC3C3; + _writeIoRegionC8CF = WriteIoRegionC8CF; + _writeRomRegionD0FF = WriteRomRegionD0FF; } public override void Initialize() @@ -88,11 +94,13 @@ public override void Initialize() _video = Machine.Video; _noSlotClock = Machine.NoSlotClock; - var romStream = StorageService.GetResourceStream("Roms/AppleIIe.rom", 0x4000); - romStream.Seek(0x0100, SeekOrigin.Current); - romStream.ReadBlock(_romInternalRegionC1CF, 0x0000, 0x0F00); - romStream.ReadBlock(_romRegionD0DF, 0x0000, 0x1000); - romStream.ReadBlock(_romRegionE0FF, 0x0000, 0x2000); + StorageService.LoadResource("Roms/AppleIIe.rom", 0x4000, stream => + { + stream.Seek(0x0100, SeekOrigin.Current); + stream.ReadBlock(_romInternalRegionC1CF, 0, _romInternalRegionC1CF.Length); + stream.ReadBlock(_romRegionD0DF, 0, _romRegionD0DF.Length); + stream.ReadBlock(_romRegionE0FF, 0, _romRegionE0FF.Length); + }); if ((ReadRomRegionE0FF(0xFBB3) == 0x06) && (ReadRomRegionE0FF(0xFBBF) == 0xC1)) { @@ -116,6 +124,55 @@ public override void Reset() // [7-3] 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); + } + #region Core Read & Write public int Read(int address) { @@ -1203,10 +1260,10 @@ private void MapRegionC0CF() _regionWrite[RegionC1C7] = null; _regionWrite[RegionC3C3] = null; _regionWrite[RegionC8CF] = null; - _writeRegion[RegionC0C0] = WriteIoRegionC0C0; - _writeRegion[RegionC1C7] = WriteIoRegionC1C7; - _writeRegion[RegionC3C3] = WriteIoRegionC3C3; - _writeRegion[RegionC8CF] = WriteIoRegionC8CF; + _writeRegion[RegionC0C0] = _writeIoRegionC0C0; + _writeRegion[RegionC1C7] = _writeIoRegionC1C7; + _writeRegion[RegionC3C3] = _writeIoRegionC3C3; + _writeRegion[RegionC8CF] = _writeIoRegionC8CF; } private void MapRegionD0FF() @@ -1248,8 +1305,8 @@ private void MapRegionD0FF() { _regionWrite[RegionD0DF] = null; _regionWrite[RegionE0FF] = null; - _writeRegion[RegionD0DF] = WriteRomRegionD0FF; - _writeRegion[RegionE0FF] = WriteRomRegionD0FF; + _writeRegion[RegionD0DF] = _writeRomRegionD0FF; + _writeRegion[RegionE0FF] = _writeRomRegionD0FF; } } @@ -1533,6 +1590,12 @@ private bool TestState(int mask, int value) public MonitorType Monitor { get; private set; } public int VideoMode { get { return StateVideoMode[_state & StateVideo]; } } + private Action _writeIoRegionC0C0; + private Action _writeIoRegionC1C7; + private Action _writeIoRegionC3C3; + private Action _writeIoRegionC8CF; + private Action _writeRomRegionD0FF; + private Keyboard _keyboard; private GamePort _gamePort; private Cassette _cassette; diff --git a/Virtu/NoSlotClock.cs b/Virtu/NoSlotClock.cs index 72574b6..9ff1292 100644 --- a/Virtu/NoSlotClock.cs +++ b/Virtu/NoSlotClock.cs @@ -1,5 +1,5 @@ using System; -using System.Collections; +using System.IO; namespace Jellyfish.Virtu { @@ -8,7 +8,42 @@ public sealed class NoSlotClock : MachineComponent public NoSlotClock(Machine machine) : base(machine) { - ResetClock(); + } + + public override void Initialize() + { + _clockEnabled = false; + _writeEnabled = true; + _clockRegister = new RingRegister(0x0, 0x1); + _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) @@ -36,18 +71,10 @@ public void Write(int address) } } - private void ResetClock() - { - // SmartWatch reset - whether tied to system reset is component specific - _comparisonRegister.Reset(); - _clockRegisterEnabled = false; - _writeEnabled = true; - } - private int ReadClock(int data) { // for a ROM, A2 high = read, and data out (if any) is on D0 - if (!_clockRegisterEnabled) + if (!_clockEnabled) { _comparisonRegister.Reset(); _writeEnabled = true; @@ -57,7 +84,7 @@ private int ReadClock(int data) data = _clockRegister.ReadBit(Machine.Video.ReadFloatingBus()); if (_clockRegister.NextBit()) { - _clockRegisterEnabled = false; + _clockEnabled = false; } return data; } @@ -70,13 +97,13 @@ private void WriteClock(int address) return; } - if (!_clockRegisterEnabled) + if (!_clockEnabled) { if ((_comparisonRegister.CompareBit(address))) { if (_comparisonRegister.NextBit()) { - _clockRegisterEnabled = true; + _clockEnabled = true; PopulateClockRegister(); } } @@ -89,7 +116,7 @@ private void WriteClock(int address) else if (_clockRegister.NextBit()) { // simulate writes, but our clock register is read-only - _clockRegisterEnabled = false; + _clockEnabled = false; } } @@ -133,18 +160,17 @@ private void PopulateClockRegister() private const ulong ClockInitSequence = 0x5CA33AC55CA33AC5; - private bool _clockRegisterEnabled; + private bool _clockEnabled; private bool _writeEnabled; - private RingRegister _clockRegister = new RingRegister(); - private RingRegister _comparisonRegister = new RingRegister(ClockInitSequence); + private RingRegister _clockRegister; + private RingRegister _comparisonRegister; - private sealed class RingRegister + private struct RingRegister { - public RingRegister(ulong data = 0) + public RingRegister(ulong data, ulong mask) { - _register = data; - - Reset(); + _data = data; + _mask = mask; } public void Reset() @@ -169,17 +195,17 @@ public void WriteBits(int data, int count) public void WriteBit(int data) { - _register = ((data & 0x1) != 0) ? (_register | _mask) : (_register & ~_mask); + _data = ((data & 0x1) != 0) ? (_data | _mask) : (_data & ~_mask); } public int ReadBit(int data) { - return ((_register & _mask) != 0) ? (data | 0x1) : (data & ~0x1); + return ((_data & _mask) != 0) ? (data | 0x1) : (data & ~0x1); } public bool CompareBit(int data) { - return (((_register & _mask) != 0) == ((data & 0x1) != 0)); + return (((_data & _mask) != 0) == ((data & 0x1) != 0)); } public bool NextBit() @@ -192,8 +218,11 @@ public bool NextBit() return false; } + public ulong Data { get { return _data; } } // no auto props + public ulong Mask { get { return _mask; } } + + private ulong _data; private ulong _mask; - private ulong _register; } } } diff --git a/Virtu/Services/AudioService.cs b/Virtu/Services/AudioService.cs index 4d83b77..8465389 100644 --- a/Virtu/Services/AudioService.cs +++ b/Virtu/Services/AudioService.cs @@ -27,8 +27,7 @@ public void Output(int data) // machine thread _index = (_index + 2) % SampleSize; if (_index == 0) { - _readEvent.Set(); - if (Machine.Settings.Cpu.IsThrottled) + if (Machine.Cpu.IsThrottled) { _writeEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock } @@ -40,18 +39,10 @@ public void Reset() Buffer.BlockCopy(SampleZero, 0, _buffer, 0, SampleSize); } - public abstract void SetVolume(double volume); // machine thread + public abstract void SetVolume(double volume); - protected void Update(int bufferSize, Action updateBuffer) // audio thread + protected void Update() // audio thread { - if (Machine.State == MachineState.Running) - { - _readEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock - } - if (updateBuffer != null) - { - updateBuffer(_buffer, bufferSize); - } _writeEvent.Set(); } @@ -64,10 +55,12 @@ protected void Update(int bufferSize, Action updateBuffer) // audio [SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] protected static readonly byte[] SampleZero = new byte[SampleSize]; + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + protected byte[] Source { get { return _buffer; } } + private byte[] _buffer = new byte[SampleSize]; private int _index; - private AutoResetEvent _readEvent = new AutoResetEvent(false); private AutoResetEvent _writeEvent = new AutoResetEvent(false); } } diff --git a/Virtu/Services/GamePortService.cs b/Virtu/Services/GamePortService.cs index 395eebb..c5f5674 100644 --- a/Virtu/Services/GamePortService.cs +++ b/Virtu/Services/GamePortService.cs @@ -1,53 +1,5 @@ namespace Jellyfish.Virtu.Services { - public struct Joystick - { - public Joystick(bool isUp, bool isLeft, bool isRight, bool isDown) - { - _isUp = isUp; - _isLeft = isLeft; - _isRight = isRight; - _isDown = isDown; - } - - public override bool Equals(object obj) - { - return ((obj is Joystick) && (this == (Joystick)obj)); - } - - public override int GetHashCode() - { - return (_isUp.GetHashCode() ^ _isLeft.GetHashCode() ^ _isRight.GetHashCode() ^ _isDown.GetHashCode()); - } - - public override string ToString() - { - return !(_isUp || _isDown || _isLeft || _isRight) ? "Position = Center" : - string.Concat("Position = ", _isUp ? "Up" : _isDown ? "Down" : string.Empty, _isLeft ? "Left" : _isRight ? "Right" : string.Empty); - } - - public static bool operator ==(Joystick joystick1, Joystick joystick2) - { - return ((joystick1._isUp == joystick2._isUp) && (joystick1._isLeft == joystick2._isLeft) && - (joystick1._isRight == joystick2._isRight) && (joystick1._isDown == joystick2._isDown)); - } - - public static bool operator !=(Joystick joystick1, Joystick joystick2) - { - return !(joystick1 == joystick2); - } - - public bool IsUp { get { return _isUp; } } // no auto props - public bool IsLeft { get { return _isLeft; } } - public bool IsRight { get { return _isRight; } } - public bool IsDown { get { return _isDown; } } - - private bool _isUp; - private bool _isLeft; - private bool _isRight; - private bool _isDown; - } - public class GamePortService : MachineService { public GamePortService(Machine machine) : @@ -63,8 +15,15 @@ public virtual void Update() { } // main thread public int Paddle2 { get; protected set; } public int Paddle3 { get; protected set; } - public Joystick Joystick0 { get; protected set; } - public Joystick Joystick1 { 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; } diff --git a/Virtu/Services/IsolatedStorageService.cs b/Virtu/Services/IsolatedStorageService.cs index c5acf62..f806261 100644 --- a/Virtu/Services/IsolatedStorageService.cs +++ b/Virtu/Services/IsolatedStorageService.cs @@ -12,7 +12,7 @@ public IsolatedStorageService(Machine machine) : { } - public override void Load(string path, Action reader) + public override void Load(string fileName, Action reader) { if (reader == null) { @@ -23,7 +23,7 @@ public override void Load(string path, Action reader) { using (var store = GetStore()) { - using (var stream = new IsolatedStorageFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, store)) + using (var stream = store.OpenFile(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { reader(stream); } @@ -37,7 +37,7 @@ public override void Load(string path, Action reader) } } - public override void Save(string path, Action writer) + public override void Save(string fileName, Action writer) { if (writer == null) { @@ -48,7 +48,7 @@ public override void Save(string path, Action writer) { using (var store = GetStore()) { - using (var stream = new IsolatedStorageFileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, store)) + using (var stream = store.OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) { writer(stream); } diff --git a/Virtu/Services/MachineServices.cs b/Virtu/Services/MachineServices.cs index 6c97f74..b8669ee 100644 --- a/Virtu/Services/MachineServices.cs +++ b/Virtu/Services/MachineServices.cs @@ -16,7 +16,7 @@ public void AddService(Type serviceType, MachineService serviceProvider) } if (_serviceProviders.ContainsKey(serviceType)) { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType"); + throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType"); } if (serviceProvider == null) { @@ -24,7 +24,7 @@ public void AddService(Type serviceType, MachineService serviceProvider) } if (!serviceType.IsAssignableFrom(serviceProvider.GetType())) { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName)); + throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName)); } _serviceProviders.Add(serviceType, serviceProvider); diff --git a/Virtu/Services/StorageService.cs b/Virtu/Services/StorageService.cs index ca2a2a5..95e4976 100644 --- a/Virtu/Services/StorageService.cs +++ b/Virtu/Services/StorageService.cs @@ -1,9 +1,9 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; -using System.Reflection; using System.Resources; +using System.Security; +using Jellyfish.Library; using Jellyfish.Virtu.Properties; namespace Jellyfish.Virtu.Services @@ -15,24 +15,128 @@ protected StorageService(Machine machine) : { } - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static Stream GetResourceStream(string resourceName, int resourceSize = 0) + public abstract void Load(string fileName, Action reader); + +#if !WINDOWS + [SecuritySafeCritical] +#endif + public static void LoadFile(string fileName, Action reader) { - var resourceManager = new ResourceManager("Jellyfish.Virtu.g", Assembly.GetExecutingAssembly()) { IgnoreCase = true }; - var resourceStream = (Stream)resourceManager.GetObject(resourceName); + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + try + { + using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + reader(stream); + } + } + catch (FileNotFoundException) + { + } + } + +#if !WINDOWS + [SecuritySafeCritical] +#endif + public static void LoadFile(FileInfo fileInfo, Action reader) + { + if (fileInfo == null) + { + throw new ArgumentNullException("fileInfo"); + } + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + try + { + using (var stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) + { + reader(stream); + } + } + catch (SecurityException) + { + } + } + + public static void LoadResource(string resourceName, int resourceSize, Action reader) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + try + { + using (var stream = GetResourceStream(resourceName, resourceSize)) + { + reader(stream); + } + } + catch (FileNotFoundException) + { + } + } + + public abstract void Save(string fileName, Action writer); + +#if !WINDOWS + [SecuritySafeCritical] +#endif + public static void SaveFile(string fileName, Action writer) + { + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + + using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + writer(stream); + } + } + +#if !WINDOWS + [SecuritySafeCritical] +#endif + public static void SaveFile(FileInfo fileInfo, Action writer) + { + if (fileInfo == null) + { + throw new ArgumentNullException("fileInfo"); + } + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + + using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write, FileShare.None)) + { + writer(stream); + } + } + + private static Stream GetResourceStream(string resourceName, int resourceSize) + { + var resourceStream = _resourceManager.Value.GetStream(resourceName, CultureInfo.CurrentUICulture); if (resourceStream == null) { - throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceNotFound, resourceName)); + throw new FileNotFoundException(string.Format(CultureInfo.CurrentUICulture, Strings.ResourceNotFound, resourceName)); } if ((resourceSize > 0) && (resourceStream.Length != resourceSize)) { - throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceInvalid, resourceName)); + throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Strings.ResourceInvalid, resourceName)); } return resourceStream; } - public abstract void Load(string path, Action reader); - public abstract void Save(string path, Action writer); + private static Lazy _resourceManager = new Lazy(() => new ResourceManager("Jellyfish.Virtu.g", typeof(StorageService).Assembly) { IgnoreCase = true }); } } diff --git a/Virtu/Services/VideoService.cs b/Virtu/Services/VideoService.cs index e56968c..3ab1498 100644 --- a/Virtu/Services/VideoService.cs +++ b/Virtu/Services/VideoService.cs @@ -7,14 +7,8 @@ protected VideoService(Machine machine) : { } + public abstract void SetFullScreen(bool isFullScreen); public abstract void SetPixel(int x, int y, uint color); public abstract void Update(); // main thread - - public void ToggleFullScreen() - { - IsFullScreen ^= true; - } - - public bool IsFullScreen { get; private set; } } } diff --git a/Virtu/Silverlight/Jellyfish.Virtu.Silverlight.csproj b/Virtu/Silverlight/Jellyfish.Virtu.Silverlight.csproj index 5a94459..65d8f45 100644 --- a/Virtu/Silverlight/Jellyfish.Virtu.Silverlight.csproj +++ b/Virtu/Silverlight/Jellyfish.Virtu.Silverlight.csproj @@ -92,9 +92,6 @@ - - True - @@ -155,9 +152,6 @@ Core\MachineEvents.cs - - Core\MachineSettings.cs - Core\Memory.cs diff --git a/Virtu/Silverlight/MainPage.xaml.cs b/Virtu/Silverlight/MainPage.xaml.cs index 6f1b65c..1757cd6 100644 --- a/Virtu/Silverlight/MainPage.xaml.cs +++ b/Virtu/Silverlight/MainPage.xaml.cs @@ -66,20 +66,16 @@ private void OnCompositionTargetRendering(object sender, EventArgs e) private void OnDiskButtonClick(int drive) { var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" }; - bool? result = dialog.ShowDialog(); if (result.HasValue && result.Value) { - using (var stream = dialog.File.OpenRead()) + _machine.Pause(); + var diskII = _machine.FindDiskIIController(); + if (diskII != null) { - _machine.Pause(); - var diskII = _machine.FindDiskIIController(); - if (diskII != null) - { - diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false); - } - _machine.Unpause(); + StorageService.LoadFile(dialog.File, stream => diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false)); } + _machine.Unpause(); } } diff --git a/Virtu/Silverlight/Phone/Jellyfish.Virtu.Silverlight.Phone.csproj b/Virtu/Silverlight/Phone/Jellyfish.Virtu.Silverlight.Phone.csproj index cfbc095..bfbc8ba 100644 --- a/Virtu/Silverlight/Phone/Jellyfish.Virtu.Silverlight.Phone.csproj +++ b/Virtu/Silverlight/Phone/Jellyfish.Virtu.Silverlight.Phone.csproj @@ -79,7 +79,6 @@ - @@ -140,9 +139,6 @@ Core\MachineEvents.cs - - Core\MachineSettings.cs - Core\Memory.cs diff --git a/Virtu/Silverlight/Phone/MainPage.xaml.cs b/Virtu/Silverlight/Phone/MainPage.xaml.cs index 742a37d..4df1174 100644 --- a/Virtu/Silverlight/Phone/MainPage.xaml.cs +++ b/Virtu/Silverlight/Phone/MainPage.xaml.cs @@ -66,16 +66,16 @@ private void OnCompositionTargetRendering(object sender, EventArgs e) //private void OnDiskButtonClick(int drive) // TODO //{ // var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" }; - // bool? result = dialog.ShowDialog(); // if (result.HasValue && result.Value) // { - // using (var stream = dialog.File.OpenRead()) + // _machine.Pause(); + // var diskII = _machine.FindDiskIIController(); + // if (diskII != null) // { - // _machine.Pause(); - // _machine.DiskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false); - // _machine.Unpause(); + // StorageService.LoadFile(dialog.File, stream => diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false)); // } + // _machine.Unpause(); // } //} diff --git a/Virtu/Silverlight/Phone/Properties/AssemblyInfo.cs b/Virtu/Silverlight/Phone/Properties/AssemblyInfo.cs index 0f15503..1463887 100644 --- a/Virtu/Silverlight/Phone/Properties/AssemblyInfo.cs +++ b/Virtu/Silverlight/Phone/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Resources; using System.Runtime.InteropServices; using Jellyfish.Library; +using Jellyfish.Virtu; [assembly: AssemblyTitle("Virtu")] [assembly: AssemblyDescription("Apple IIe Emulator")] @@ -11,9 +12,9 @@ [assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")] -[assembly: AssemblyVersion("0.8.3.0")] -[assembly: AssemblyFileVersion("0.8.3.0")] -[assembly: AssemblyInformationalVersion("0.8.3.0")] +[assembly: AssemblyVersion(Machine.Version)] +[assembly: AssemblyFileVersion(Machine.Version)] +[assembly: AssemblyInformationalVersion(Machine.Version)] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Virtu/Silverlight/Properties/AssemblyInfo.cs b/Virtu/Silverlight/Properties/AssemblyInfo.cs index 43c2de1..a0bd1f1 100644 --- a/Virtu/Silverlight/Properties/AssemblyInfo.cs +++ b/Virtu/Silverlight/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Resources; using System.Runtime.InteropServices; using Jellyfish.Library; +using Jellyfish.Virtu; [assembly: AssemblyTitle("Virtu")] [assembly: AssemblyDescription("Apple IIe Emulator")] @@ -11,9 +12,9 @@ [assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")] -[assembly: AssemblyVersion("0.8.3.0")] -[assembly: AssemblyFileVersion("0.8.3.0")] -[assembly: AssemblyInformationalVersion("0.8.3.0")] +[assembly: AssemblyVersion(Machine.Version)] +[assembly: AssemblyFileVersion(Machine.Version)] +[assembly: AssemblyInformationalVersion(Machine.Version)] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Virtu/Silverlight/Services/SilverlightAudioService.cs b/Virtu/Silverlight/Services/SilverlightAudioService.cs index 57d0e6d..802aed2 100644 --- a/Virtu/Silverlight/Services/SilverlightAudioService.cs +++ b/Virtu/Silverlight/Services/SilverlightAudioService.cs @@ -28,9 +28,9 @@ public SilverlightAudioService(Machine machine, UserControl page, MediaElement m #endif } - public override void SetVolume(double volume) // machine thread + public override void SetVolume(double volume) { - _media.Dispatcher.BeginInvoke(() => _media.Volume = volume); + _media.Dispatcher.Send(() => _media.Volume = volume); } protected override void Dispose(bool disposing) @@ -50,7 +50,8 @@ private void OnMediaSourceUpdate(byte[] buffer, int bufferSize) // audio thread // DebugService.WriteLine("OnMediaSourceUpdate"); //} - Update(bufferSize, (source, count) => Buffer.BlockCopy(source, 0, buffer, 0, count)); + Buffer.BlockCopy(Source, 0, buffer, 0, bufferSize); + Update(); } private MediaElement _media; diff --git a/Virtu/Silverlight/Services/SilverlightDebugService.cs b/Virtu/Silverlight/Services/SilverlightDebugService.cs index 1c355fc..bdf938e 100644 --- a/Virtu/Silverlight/Services/SilverlightDebugService.cs +++ b/Virtu/Silverlight/Services/SilverlightDebugService.cs @@ -18,7 +18,7 @@ public SilverlightDebugService(Machine machine, MainPage page) : protected override void OnWriteLine(string message) { - _page.Dispatcher.CheckBeginInvoke(() => _page.WriteLine(message + Environment.NewLine)); + _page.Dispatcher.Post(() => _page.WriteLine(message + Environment.NewLine)); } private MainPage _page; diff --git a/Virtu/Silverlight/Services/SilverlightKeyboardService.cs b/Virtu/Silverlight/Services/SilverlightKeyboardService.cs index 7c90c52..b56f730 100644 --- a/Virtu/Silverlight/Services/SilverlightKeyboardService.cs +++ b/Virtu/Silverlight/Services/SilverlightKeyboardService.cs @@ -93,17 +93,18 @@ private void OnPageKeyUp(object sender, KeyEventArgs e) } else if (control && (e.Key == Key.Divide)) { - Machine.Cpu.ToggleThrottle(); + Machine.Cpu.IsThrottled ^= true; } else if (control && (e.Key == Key.Multiply)) { - Machine.Video.ToggleMonochrome(); + Machine.Video.IsMonochrome ^= true; } +#if !WINDOWS_PHONE else if (control && (e.Key == Key.Subtract)) { - Machine.Video.ToggleFullScreen(); + Machine.Video.IsFullScreen ^= true; } - +#endif Update(); } diff --git a/Virtu/Silverlight/Services/SilverlightVideoService.cs b/Virtu/Silverlight/Services/SilverlightVideoService.cs index dda8d97..36d4613 100644 --- a/Virtu/Silverlight/Services/SilverlightVideoService.cs +++ b/Virtu/Silverlight/Services/SilverlightVideoService.cs @@ -3,6 +3,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; +using Jellyfish.Library; #if WINDOWS_PHONE using Microsoft.Phone.Controls; #endif @@ -35,6 +36,24 @@ public SilverlightVideoService(Machine machine, UserControl page, Image image) : _page.SizeChanged += (sender, e) => SetImageSize(); } + public override void SetFullScreen(bool isFullScreen) + { +#if !WINDOWS_PHONE + _page.Dispatcher.Send(() => + { + var application = Application.Current; + if (application.IsRunningOutOfBrowser) + { + var content = application.Host.Content; + if (content.IsFullScreen != isFullScreen) + { + content.IsFullScreen = isFullScreen; + } + } + }); +#endif + } + [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")] public override void SetPixel(int x, int y, uint color) { @@ -44,13 +63,6 @@ public override void SetPixel(int x, int y, uint color) public override void Update() // main thread { -#if !WINDOWS_PHONE - var content = Application.Current.Host.Content; - if (Application.Current.IsRunningOutOfBrowser && (content.IsFullScreen != IsFullScreen)) - { - Application.Current.RootVisual.Dispatcher.BeginInvoke(() => content.IsFullScreen = IsFullScreen); // queue to dispatcher; avoids crash! - } -#endif if (_pixelsDirty) { _pixelsDirty = false; @@ -68,17 +80,17 @@ private void SetImageSize(bool swapOrientation = false) Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight)); _image.Width = uniformScale * BitmapWidth; _image.Height = uniformScale * BitmapHeight; - Machine.Video.DirtyScreen(); } #if !WINDOWS_PHONE private void SetWindowSizeToContent() { - if (Application.Current.IsRunningOutOfBrowser && !_sizedToContent) + var application = Application.Current; + if (application.IsRunningOutOfBrowser && !_sizedToContent) { _sizedToContent = true; - var window = Application.Current.MainWindow; - var size = Application.Current.RootVisual.DesiredSize; + var window = application.MainWindow; + var size = application.RootVisual.DesiredSize; window.Width = size.Width; window.Height = size.Height; } diff --git a/Virtu/Speaker.cs b/Virtu/Speaker.cs index 6f98d70..7a55033 100644 --- a/Virtu/Speaker.cs +++ b/Virtu/Speaker.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using Jellyfish.Virtu.Services; namespace Jellyfish.Virtu @@ -15,10 +16,12 @@ public override void Initialize() { _audioService = Machine.Services.GetService(); - UpdateSettings(); - Machine.Video.VSync += (sender, e) => UpdateSettings(); - - Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent); +#if WINDOWS_PHONE + Volume = 0.85; +#else + Volume = 0.5; +#endif + Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent); } public override void Reset() @@ -28,6 +31,26 @@ public override void Reset() _highCycles = _totalCycles = 0; } + public override void LoadState(BinaryReader reader, Version version) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + Volume = reader.ReadDouble(); + } + + public override void SaveState(BinaryWriter writer) + { + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + + writer.Write(Volume); + } + public void ToggleOutput() { UpdateCycles(); @@ -40,7 +63,7 @@ private void FlushOutputEvent() _audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation _highCycles = _totalCycles = 0; - Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent); + Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent); } private void UpdateCycles() @@ -54,20 +77,18 @@ private void UpdateCycles() _lastCycles = Machine.Cpu.Cycles; } - private void UpdateSettings() - { - _audioService.SetVolume(Machine.Settings.Audio.Volume); - } + public double 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 AudioService _audioService; + private double _volume; } } diff --git a/Virtu/Video.cs b/Virtu/Video.cs index e52a4c1..f1dbd64 100644 --- a/Virtu/Video.cs +++ b/Virtu/Video.cs @@ -1,9 +1,12 @@ using System; +using System.IO; using Jellyfish.Virtu.Services; -using Jellyfish.Virtu.Settings; namespace Jellyfish.Virtu { + [Flags] + public enum ScannerOptions { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc + public sealed partial class Video : MachineComponent { public Video(Machine machine) : @@ -26,7 +29,29 @@ public override void Initialize() _memory = Machine.Memory; _videoService = Machine.Services.GetService(); - UpdateSettings(); + _colorBlack = 0xFF000000; // BGRA + _colorDarkBlue = 0xFF000099; + _colorDarkGreen = 0xFF117722; + _colorMediumBlue = 0xFF0000FF; + _colorBrown = 0xFF885500; + _colorLightGrey = 0xFF99AAAA; + _colorGreen = 0xFF00EE11; + _colorAquamarine = 0xFF55FFAA; + _colorDeepRed = 0xFFFF1111; + _colorPurple = 0xFFDD00DD; + _colorDarkGrey = 0xFF445555; + _colorLightBlue = 0xFF33AAFF; + _colorOrange = 0xFFFF4411; + _colorPink = 0xFFFF9988; + _colorYellow = 0xFFFFFF11; + _colorWhite = 0xFFFFFFFF; + _colorMonochrome = 0xFF00AA00; + SetPalette(); + + IsFullScreen = false; + IsMonochrome = false; + ScannerOptions = ScannerOptions.None; + IsVBlank = true; Machine.Events.AddEvent(_cyclesPerVBlankPreset, _leaveVBlankEvent); // align flush events with scanner; assumes vcount preset at start of frame [3-15, 3-16] @@ -41,6 +66,71 @@ public override void Reset() 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; @@ -123,25 +213,10 @@ public void SetCharSet() DirtyScreenText(); } - public void ToggleFullScreen() - { - Machine.Settings.Video.IsFullScreen ^= true; - _videoService.ToggleFullScreen(); - DirtyScreen(); - FlushScreen(); - } - - public void ToggleMonochrome() - { - Machine.Settings.Video.IsMonochrome ^= true; - DirtyScreen(); - FlushScreen(); - } - #region Draw Methods private void DrawText40(int data, int x, int y) { - int color = Machine.Settings.Video.IsMonochrome ? ColorMono00 : ColorWhite00; + int color = IsMonochrome ? ColorMono00 : ColorWhite00; int index = _charSet[data] * CharBitmapBytes; int inverseMask = (_isTextInversed && !_memory.IsCharSetAlternate && (0x40 <= data) && (data <= 0x7F)) ? 0x7F : 0x00; for (int i = 0; i < TextHeight; i++, y++) @@ -166,7 +241,7 @@ private void DrawText40(int data, int x, int y) private void DrawText80(int data, int x, int y) { - int color = Machine.Settings.Video.IsMonochrome ? ColorMono00 : ColorWhite00; + int color = IsMonochrome ? ColorMono00 : ColorWhite00; int index = _charSet[data] * CharBitmapBytes; int mask = (_isTextInversed && !_memory.IsCharSetAlternate && (0x40 <= data) && (data <= 0x7F)) ? 0x7F : 0x00; for (int i = 0; i < TextHeight; i++, y++) @@ -184,7 +259,7 @@ private void DrawText80(int data, int x, int y) private void DrawLores(int data, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { if ((x & 0x02) == 0x02) // odd cell { @@ -268,7 +343,7 @@ private void DrawLores(int data, int x, int y) private void Draw7MLores(int data, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { if ((x & 0x02) == 0x02) // odd cell { @@ -352,7 +427,7 @@ private void Draw7MLores(int data, int x, int y) private void DrawDLores(int data, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { if ((x & 0x01) == 0x00) // even half cell { @@ -408,7 +483,7 @@ private void DrawDLores(int data, int x, int y) private void DrawHires(int address, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { int data = _memory.ReadRamMainRegion02BF(address); SetPixel(x + 0, y, data & 0x01); @@ -466,7 +541,7 @@ private void DrawHires(int address, int x, int y) private void DrawNDHires(int address, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { int data = _memory.ReadRamMainRegion02BF(address); SetPixel(x + 0, y, data & 0x01); @@ -524,7 +599,7 @@ private void DrawNDHires(int address, int x, int y) private void DrawDHiresA(int address, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { if ((x & 0x2) == 0x00) // even cell { @@ -592,7 +667,7 @@ private void DrawDHiresA(int address, int x, int y) private void DrawDHiresM(int address, int x, int y) { - if (Machine.Settings.Video.IsMonochrome) + if (IsMonochrome) { if ((x & 0x2) == 0x02) // odd cell { @@ -919,64 +994,58 @@ private void LeaveVBlankEvent() private void ResetVSyncEvent() { - UpdateSettings(); - - var handler = VSync; - if (handler != null) - { - handler(this, EventArgs.Empty); - } - Machine.Events.AddEvent(_cyclesPerVSync, _resetVSyncEvent); } + private void SetPalette() + { + _colorPalette[ColorMono00] = _colorBlack; + _colorPalette[ColorMono01] = _colorMonochrome; + _colorPalette[ColorMono02] = _colorMonochrome; + _colorPalette[ColorMono04] = _colorMonochrome; + _colorPalette[ColorMono08] = _colorMonochrome; + _colorPalette[ColorMono10] = _colorMonochrome; + _colorPalette[ColorMono20] = _colorMonochrome; + _colorPalette[ColorMono40] = _colorMonochrome; + _colorPalette[ColorMono80] = _colorMonochrome; + + _colorPalette[ColorWhite00] = _colorBlack; + _colorPalette[ColorWhite01] = _colorWhite; + _colorPalette[ColorWhite02] = _colorWhite; + _colorPalette[ColorWhite04] = _colorWhite; + _colorPalette[ColorWhite08] = _colorWhite; + _colorPalette[ColorWhite10] = _colorWhite; + _colorPalette[ColorWhite20] = _colorWhite; + _colorPalette[ColorWhite40] = _colorWhite; + _colorPalette[ColorWhite80] = _colorWhite; + + _colorPalette[ColorDHires0] = _colorBlack; + _colorPalette[ColorDHires1] = _colorDarkBlue; + _colorPalette[ColorDHires2] = _colorDarkGreen; + _colorPalette[ColorDHires3] = _colorMediumBlue; + _colorPalette[ColorDHires4] = _colorBrown; + _colorPalette[ColorDHires5] = _colorLightGrey; + _colorPalette[ColorDHires6] = _colorGreen; + _colorPalette[ColorDHires7] = _colorAquamarine; + _colorPalette[ColorDHires8] = _colorDeepRed; + _colorPalette[ColorDHires9] = _colorPurple; + _colorPalette[ColorDHiresA] = _colorDarkGrey; + _colorPalette[ColorDHiresB] = _colorLightBlue; + _colorPalette[ColorDHiresC] = _colorOrange; + _colorPalette[ColorDHiresD] = _colorPink; + _colorPalette[ColorDHiresE] = _colorYellow; + _colorPalette[ColorDHiresF] = _colorWhite; + + DirtyScreen(); + } + private void SetPixel(int x, int y, int color) { _videoService.SetPixel(x, 2 * y, _colorPalette[color]); } - private void UpdateSettings() + private void SetScanner() { - var settings = Machine.Settings.Video; - - _colorPalette[ColorMono00] = settings.Color.Black; - _colorPalette[ColorMono01] = settings.Color.Monochrome; - _colorPalette[ColorMono02] = settings.Color.Monochrome; - _colorPalette[ColorMono04] = settings.Color.Monochrome; - _colorPalette[ColorMono08] = settings.Color.Monochrome; - _colorPalette[ColorMono10] = settings.Color.Monochrome; - _colorPalette[ColorMono20] = settings.Color.Monochrome; - _colorPalette[ColorMono40] = settings.Color.Monochrome; - _colorPalette[ColorMono80] = settings.Color.Monochrome; - - _colorPalette[ColorWhite00] = settings.Color.Black; - _colorPalette[ColorWhite01] = settings.Color.White; - _colorPalette[ColorWhite02] = settings.Color.White; - _colorPalette[ColorWhite04] = settings.Color.White; - _colorPalette[ColorWhite08] = settings.Color.White; - _colorPalette[ColorWhite10] = settings.Color.White; - _colorPalette[ColorWhite20] = settings.Color.White; - _colorPalette[ColorWhite40] = settings.Color.White; - _colorPalette[ColorWhite80] = settings.Color.White; - - _colorPalette[ColorDHires0] = settings.Color.Black; - _colorPalette[ColorDHires1] = settings.Color.DarkBlue; - _colorPalette[ColorDHires2] = settings.Color.DarkGreen; - _colorPalette[ColorDHires3] = settings.Color.MediumBlue; - _colorPalette[ColorDHires4] = settings.Color.Brown; - _colorPalette[ColorDHires5] = settings.Color.LightGrey; - _colorPalette[ColorDHires6] = settings.Color.Green; - _colorPalette[ColorDHires7] = settings.Color.Aquamarine; - _colorPalette[ColorDHires8] = settings.Color.DeepRed; - _colorPalette[ColorDHires9] = settings.Color.Purple; - _colorPalette[ColorDHiresA] = settings.Color.DarkGrey; - _colorPalette[ColorDHiresB] = settings.Color.LightBlue; - _colorPalette[ColorDHiresC] = settings.Color.Orange; - _colorPalette[ColorDHiresD] = settings.Color.Pink; - _colorPalette[ColorDHiresE] = settings.Color.Yellow; - _colorPalette[ColorDHiresF] = settings.Color.White; - - _scannerOptions = settings.ScannerOptions; if ((_scannerOptions & ScannerOptions.Pal) != 0) { _vCountPreset = VCountPresetPal; @@ -992,17 +1061,31 @@ private void UpdateSettings() _cyclesPerVBlankPreset = (_vLineLeaveVBlank - VLineTriggerPreset) * CyclesPerHSync; // cycles during vblank after vcount preset [3-15, 3-16] _cyclesPerVSync = _vLineLeaveVBlank * CyclesPerHSync; _cyclesPerFlash = VSyncsPerFlash * _cyclesPerVSync; - - if (_videoService.IsFullScreen != settings.IsFullScreen) - { - _videoService.ToggleFullScreen(); - } } - public bool IsVBlank { get; private set; } - public long TicksPerVSync { get { return TimeSpan.FromSeconds((double)_cyclesPerVSync / CyclesPerSecond).Ticks; } } + 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 event EventHandler VSync; + public bool IsFullScreen { get { return _isFullScreen; } set { _isFullScreen = value; _videoService.SetFullScreen(_isFullScreen); } } + public bool IsMonochrome { get { return _isMonochrome; } set { _isMonochrome = value; DirtyScreen(); } } + public ScannerOptions ScannerOptions { get { return _scannerOptions; } set { _scannerOptions = value; SetScanner(); } } + + public bool IsVBlank { get; private set; } private Action _flushRowEvent; private Action _inverseTextEvent; @@ -1012,16 +1095,36 @@ private void UpdateSettings() private Memory _memory; private VideoService _videoService; - private ushort[] _charSet; - private uint[] _colorPalette = new uint[ColorPaletteCount]; - private bool[] _isCellDirty = new bool[Height * CellColumns + 1]; // includes sentinel + private uint _colorBlack; + private uint _colorDarkBlue; + private uint _colorDarkGreen; + private uint _colorMediumBlue; + private uint _colorBrown; + private uint _colorLightGrey; + private uint _colorGreen; + private uint _colorAquamarine; + private uint _colorDeepRed; + private uint _colorPurple; + private uint _colorDarkGrey; + private uint _colorLightBlue; + private uint _colorOrange; + private uint _colorPink; + private uint _colorYellow; + private uint _colorWhite; + private uint _colorMonochrome; + private bool _isFullScreen; + private bool _isMonochrome; private bool _isTextInversed; + private ScannerOptions _scannerOptions; private int _cyclesPerVBlank; private int _cyclesPerVBlankPreset; private int _cyclesPerVSync; private int _cyclesPerFlash; private int _vCountPreset; private int _vLineLeaveVBlank; - private ScannerOptions _scannerOptions; + + private ushort[] _charSet; + private uint[] _colorPalette = new uint[ColorPaletteCount]; + private bool[] _isCellDirty = new bool[Height * CellColumns + 1]; // includes sentinel } } diff --git a/Virtu/Wpf/Jellyfish.Virtu.Wpf.csproj b/Virtu/Wpf/Jellyfish.Virtu.Wpf.csproj index 6dbffec..ad9681f 100644 --- a/Virtu/Wpf/Jellyfish.Virtu.Wpf.csproj +++ b/Virtu/Wpf/Jellyfish.Virtu.Wpf.csproj @@ -74,7 +74,6 @@ 4.0 - @@ -145,9 +144,6 @@ Core\MachineEvents.cs - - Core\MachineSettings.cs - Core\Memory.cs diff --git a/Virtu/Wpf/MainPage.xaml.cs b/Virtu/Wpf/MainPage.xaml.cs index f874ad8..9a51b7c 100644 --- a/Virtu/Wpf/MainPage.xaml.cs +++ b/Virtu/Wpf/MainPage.xaml.cs @@ -68,29 +68,16 @@ private void OnCompositionTargetRendering(object sender, EventArgs e) private void OnDiskButtonClick(int drive) { var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" }; - bool? result = dialog.ShowDialog(); if (result.HasValue && result.Value) { - using (var stream = File.OpenRead(dialog.FileName)) + _machine.Pause(); + var diskII = _machine.FindDiskIIController(); + if (diskII != null) { - _machine.Pause(); - var diskII = _machine.FindDiskIIController(); - if (diskII != null) - { - diskII.Drives[drive].InsertDisk(dialog.FileName, stream, false); - var settings = _machine.Settings.DiskII; - if (drive == 0) - { - settings.Disk1.Name = dialog.FileName; - } - else - { - settings.Disk2.Name = dialog.FileName; - } - } - _machine.Unpause(); + StorageService.LoadFile(dialog.FileName, stream => diskII.Drives[drive].InsertDisk(dialog.FileName, stream, false)); } + _machine.Unpause(); } } diff --git a/Virtu/Wpf/Properties/AssemblyInfo.cs b/Virtu/Wpf/Properties/AssemblyInfo.cs index 02dd19e..d3d6287 100644 --- a/Virtu/Wpf/Properties/AssemblyInfo.cs +++ b/Virtu/Wpf/Properties/AssemblyInfo.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Windows; using Jellyfish.Library; +using Jellyfish.Virtu; [assembly: AssemblyTitle("Virtu")] [assembly: AssemblyDescription("Apple IIe Emulator")] @@ -12,9 +13,9 @@ [assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")] -[assembly: AssemblyVersion("0.8.3.0")] -[assembly: AssemblyFileVersion("0.8.3.0")] -[assembly: AssemblyInformationalVersion("0.8.3.0")] +[assembly: AssemblyVersion(Machine.Version)] +[assembly: AssemblyFileVersion(Machine.Version)] +[assembly: AssemblyInformationalVersion(Machine.Version)] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Virtu/Wpf/Services/WpfAudioService.cs b/Virtu/Wpf/Services/WpfAudioService.cs index 08c831b..ad41c61 100644 --- a/Virtu/Wpf/Services/WpfAudioService.cs +++ b/Virtu/Wpf/Services/WpfAudioService.cs @@ -28,7 +28,7 @@ public WpfAudioService(Machine machine, UserControl page) : }; } - public override void SetVolume(double volume) // machine thread + public override void SetVolume(double volume) { _directSound.SetVolume(volume); } @@ -50,7 +50,8 @@ private void OnDirectSoundUpdate(IntPtr buffer, int bufferSize) // audio thread // DebugService.WriteLine("OnDirectSoundUpdate"); //} - Update(bufferSize, (source, count) => Marshal.Copy(source, 0, buffer, count)); + Marshal.Copy(Source, 0, buffer, bufferSize); + Update(); } private DirectSound _directSound; diff --git a/Virtu/Wpf/Services/WpfDebugService.cs b/Virtu/Wpf/Services/WpfDebugService.cs index 9c77ea9..6eefa8c 100644 --- a/Virtu/Wpf/Services/WpfDebugService.cs +++ b/Virtu/Wpf/Services/WpfDebugService.cs @@ -18,7 +18,7 @@ public WpfDebugService(Machine machine, MainPage page) : protected override void OnWriteLine(string message) { - _page.Dispatcher.CheckInvoke(() => _page.WriteLine(message + Environment.NewLine)); + _page.Dispatcher.Post(() => _page.WriteLine(message + Environment.NewLine)); } private MainPage _page; diff --git a/Virtu/Wpf/Services/WpfKeyboardService.cs b/Virtu/Wpf/Services/WpfKeyboardService.cs index b733407..c3e4e75 100644 --- a/Virtu/Wpf/Services/WpfKeyboardService.cs +++ b/Virtu/Wpf/Services/WpfKeyboardService.cs @@ -88,15 +88,15 @@ private void OnPageKeyUp(object sender, KeyEventArgs e) if (control && (e.Key == Key.Divide)) { - Machine.Cpu.ToggleThrottle(); + Machine.Cpu.IsThrottled ^= true; } else if (control && (e.Key == Key.Multiply)) { - Machine.Video.ToggleMonochrome(); + Machine.Video.IsMonochrome ^= true; } else if (control && (e.Key == Key.Subtract)) { - Machine.Video.ToggleFullScreen(); + Machine.Video.IsFullScreen ^= true; } Update(); diff --git a/Virtu/Wpf/Services/WpfVideoService.cs b/Virtu/Wpf/Services/WpfVideoService.cs index fcd2f34..0e4ad3d 100644 --- a/Virtu/Wpf/Services/WpfVideoService.cs +++ b/Virtu/Wpf/Services/WpfVideoService.cs @@ -4,6 +4,7 @@ using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; +using Jellyfish.Library; namespace Jellyfish.Virtu.Services { @@ -29,6 +30,30 @@ public WpfVideoService(Machine machine, UserControl page, Image image) : _page.SizeChanged += (sender, e) => SetImageSize(); } + public override void SetFullScreen(bool isFullScreen) + { + if (_isFullScreen != isFullScreen) + { + _isFullScreen = isFullScreen; + _page.Dispatcher.Send(() => + { + var window = Window.GetWindow(_page); + if (_isFullScreen) + { + window.ResizeMode = ResizeMode.NoResize; + window.WindowStyle = WindowStyle.None; + window.WindowState = WindowState.Maximized; + } + else + { + window.WindowState = WindowState.Normal; + window.WindowStyle = WindowStyle.SingleBorderWindow; + window.ResizeMode = ResizeMode.CanResize; + } + }); + } + } + [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")] public override void SetPixel(int x, int y, uint color) { @@ -38,24 +63,6 @@ public override void SetPixel(int x, int y, uint color) public override void Update() // main thread { - if (_isFullScreen != IsFullScreen) - { - var window = Window.GetWindow(_page); - if (IsFullScreen) - { - window.ResizeMode = ResizeMode.NoResize; - window.WindowStyle = WindowStyle.None; - window.WindowState = WindowState.Maximized; - } - else - { - window.WindowState = WindowState.Normal; - window.WindowStyle = WindowStyle.SingleBorderWindow; - window.ResizeMode = ResizeMode.CanResize; - } - _isFullScreen = IsFullScreen; - } - if (_pixelsDirty) { _pixelsDirty = false; @@ -68,7 +75,6 @@ private void SetImageSize() int uniformScale = Math.Max(1, Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight)); _image.Width = uniformScale * BitmapWidth; _image.Height = uniformScale * BitmapHeight; - Machine.Video.DirtyScreen(); } private void SetWindowSizeToContent() diff --git a/Virtu/Xna/Jellyfish.Virtu.Xna.Phone.csproj b/Virtu/Xna/Jellyfish.Virtu.Xna.Phone.csproj index fbbd0a2..32bec19 100644 --- a/Virtu/Xna/Jellyfish.Virtu.Xna.Phone.csproj +++ b/Virtu/Xna/Jellyfish.Virtu.Xna.Phone.csproj @@ -102,9 +102,6 @@ False - - False - @@ -149,9 +146,6 @@ Core\MachineEvents.cs - - Core\MachineSettings.cs - Core\Memory.cs diff --git a/Virtu/Xna/Jellyfish.Virtu.Xna.Xbox.csproj b/Virtu/Xna/Jellyfish.Virtu.Xna.Xbox.csproj index d497617..5d01606 100644 --- a/Virtu/Xna/Jellyfish.Virtu.Xna.Xbox.csproj +++ b/Virtu/Xna/Jellyfish.Virtu.Xna.Xbox.csproj @@ -108,9 +108,6 @@ False - - False - @@ -155,9 +152,6 @@ Core\MachineEvents.cs - - Core\MachineSettings.cs - Core\Memory.cs diff --git a/Virtu/Xna/Jellyfish.Virtu.Xna.csproj b/Virtu/Xna/Jellyfish.Virtu.Xna.csproj index 35e2bd6..45a553a 100644 --- a/Virtu/Xna/Jellyfish.Virtu.Xna.csproj +++ b/Virtu/Xna/Jellyfish.Virtu.Xna.csproj @@ -112,9 +112,6 @@ False - - False - @@ -159,9 +156,6 @@ Core\MachineEvents.cs - - Core\MachineSettings.cs - Core\Memory.cs diff --git a/Virtu/Xna/Properties/AssemblyInfo.cs b/Virtu/Xna/Properties/AssemblyInfo.cs index cad7758..0179ef6 100644 --- a/Virtu/Xna/Properties/AssemblyInfo.cs +++ b/Virtu/Xna/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Resources; using System.Runtime.InteropServices; using Jellyfish.Library; +using Jellyfish.Virtu; [assembly: AssemblyTitle("Virtu")] [assembly: AssemblyDescription("Apple IIe Emulator")] @@ -17,9 +18,9 @@ [assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")] [assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")] -[assembly: AssemblyVersion("0.8.3.0")] -[assembly: AssemblyFileVersion("0.8.3.0")] -[assembly: AssemblyInformationalVersion("0.8.3.0")] +[assembly: AssemblyVersion(Machine.Version)] +[assembly: AssemblyFileVersion(Machine.Version)] +[assembly: AssemblyInformationalVersion(Machine.Version)] [assembly: CLSCompliant(false)] [assembly: ComVisible(false)] diff --git a/Virtu/Xna/Services/XnaAudioService.cs b/Virtu/Xna/Services/XnaAudioService.cs index 5b8e672..f8a7c87 100644 --- a/Virtu/Xna/Services/XnaAudioService.cs +++ b/Virtu/Xna/Services/XnaAudioService.cs @@ -23,7 +23,7 @@ public XnaAudioService(Machine machine, GameBase game) : _dynamicSoundEffect.Play(); } - public override void SetVolume(double volume) // machine thread + public override void SetVolume(double volume) { _dynamicSoundEffect.Volume = (float)volume; } @@ -45,7 +45,8 @@ private void OnDynamicSoundEffectBufferNeeded(object sender, EventArgs e) // aud // DebugService.WriteLine("OnDynamicSoundEffectBufferNeeded"); //} - Update(SampleSize, (source, count) => _dynamicSoundEffect.SubmitBuffer(source, 0, count)); + _dynamicSoundEffect.SubmitBuffer(Source, 0, SampleSize); + Update(); } private GameBase _game; diff --git a/Virtu/Xna/Services/XnaGamePortService.cs b/Virtu/Xna/Services/XnaGamePortService.cs index 89fddab..6c2b40e 100644 --- a/Virtu/Xna/Services/XnaGamePortService.cs +++ b/Virtu/Xna/Services/XnaGamePortService.cs @@ -20,14 +20,22 @@ public override void Update() // main thread var left = _state.ThumbSticks.Left; var right = _state.ThumbSticks.Right; var dpad = _state.DPad; + float joystickDeadZone = (float)Machine.GamePort.JoystickDeadZone; Paddle0 = (int)((1 + left.X) * PaddleScale); Paddle1 = (int)((1 - left.Y) * PaddleScale); // invert y Paddle2 = (int)((1 + right.X) * PaddleScale); Paddle3 = (int)((1 - right.Y) * PaddleScale); // invert y - Joystick0 = GetJoystick(ref left, ref dpad); - Joystick1 = GetJoystick(ref right); + IsJoystick0Up = ((left.Y > joystickDeadZone) || (dpad.Up == ButtonState.Pressed)); + IsJoystick0Left = ((left.X < -joystickDeadZone) || (dpad.Left == ButtonState.Pressed)); + IsJoystick0Right = ((left.X > joystickDeadZone) || (dpad.Right == ButtonState.Pressed)); + IsJoystick0Down = ((left.Y < -joystickDeadZone) || (dpad.Down == ButtonState.Pressed)); + + IsJoystick1Up = (right.Y > joystickDeadZone); + IsJoystick1Left = (right.X < -joystickDeadZone); + IsJoystick1Right = (right.X > joystickDeadZone); + IsJoystick1Down = (right.Y < -joystickDeadZone); IsButton0Down = ((_state.Buttons.A == ButtonState.Pressed) || (_state.Buttons.LeftShoulder == ButtonState.Pressed)); IsButton1Down = ((_state.Buttons.B == ButtonState.Pressed) || (_state.Buttons.RightShoulder == ButtonState.Pressed)); @@ -35,28 +43,7 @@ public override void Update() // main thread } } - private static Joystick GetJoystick(ref Vector2 thumbstick) - { - bool isUp = (thumbstick.Y > JoystickDeadZone); - bool isLeft = (thumbstick.X < -JoystickDeadZone); - bool isRight = (thumbstick.X > JoystickDeadZone); - bool isDown = (thumbstick.Y < -JoystickDeadZone); - - return new Joystick(isUp, isLeft, isRight, isDown); - } - - private static Joystick GetJoystick(ref Vector2 thumbstick, ref GamePadDPad dpad) - { - bool isUp = ((thumbstick.Y > JoystickDeadZone) || (dpad.Up == ButtonState.Pressed)); - bool isLeft = ((thumbstick.X < -JoystickDeadZone) || (dpad.Left == ButtonState.Pressed)); - bool isRight = ((thumbstick.X > JoystickDeadZone) || (dpad.Right == ButtonState.Pressed)); - bool isDown = ((thumbstick.Y < -JoystickDeadZone) || (dpad.Down == ButtonState.Pressed)); - - return new Joystick(isUp, isLeft, isRight, isDown); - } - private const int PaddleScale = 128; - private const float JoystickDeadZone = 0.5f; private GamePadState _state; private GamePadState _lastState; diff --git a/Virtu/Xna/Services/XnaKeyboardService.cs b/Virtu/Xna/Services/XnaKeyboardService.cs index 92a4dc5..2fda62d 100644 --- a/Virtu/Xna/Services/XnaKeyboardService.cs +++ b/Virtu/Xna/Services/XnaKeyboardService.cs @@ -105,16 +105,16 @@ private void OnKeyUp(Keys key, bool gamePadControl) } else if ((control && (key == Keys.Divide)) || (gamePadControl && (key == Keys.D8))) { - Machine.Cpu.ToggleThrottle(); + Machine.Cpu.IsThrottled ^= true; } else if ((control && (key == Keys.Multiply)) || (gamePadControl && (key == Keys.D9))) { - Machine.Video.ToggleMonochrome(); + Machine.Video.IsMonochrome ^= true; } #if WINDOWS else if ((control && (key == Keys.Subtract)) || (gamePadControl && (key == Keys.D0))) { - Machine.Video.ToggleFullScreen(); + Machine.Video.IsFullScreen ^= true; } #endif } diff --git a/Virtu/Xna/Services/XnaStorageService.cs b/Virtu/Xna/Services/XnaStorageService.cs index 7a593e5..29675a2 100644 --- a/Virtu/Xna/Services/XnaStorageService.cs +++ b/Virtu/Xna/Services/XnaStorageService.cs @@ -18,7 +18,7 @@ public XnaStorageService(Machine machine, GameBase game) : _game = game; } - public override void Load(string path, Action reader) + public override void Load(string fileName, Action reader) { if (reader == null) { @@ -29,7 +29,7 @@ public override void Load(string path, Action reader) { using (var storageContainer = OpenContainer()) { - using (var stream = storageContainer.OpenFile(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var stream = storageContainer.OpenFile(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { reader(stream); } @@ -40,7 +40,7 @@ public override void Load(string path, Action reader) } } - public override void Save(string path, Action writer) + public override void Save(string fileName, Action writer) { if (writer == null) { @@ -49,7 +49,7 @@ public override void Save(string path, Action writer) using (var storageContainer = OpenContainer()) { - using (var stream = storageContainer.OpenFile(path, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = storageContainer.OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) { writer(stream); } diff --git a/Virtu/Xna/Services/XnaVideoService.cs b/Virtu/Xna/Services/XnaVideoService.cs index 8716004..6c4e6e4 100644 --- a/Virtu/Xna/Services/XnaVideoService.cs +++ b/Virtu/Xna/Services/XnaVideoService.cs @@ -26,6 +26,18 @@ public XnaVideoService(Machine machine, GameBase game) : _game.GraphicsDeviceService.DeviceReset += (sender, e) => SetTexturePosition(); } + public override void SetFullScreen(bool isFullScreen) + { +#if WINDOWS + var graphicsDeviceManager = _game.GraphicsDeviceManager; + if (graphicsDeviceManager.IsFullScreen != isFullScreen) + { + graphicsDeviceManager.IsFullScreen = isFullScreen; + _game.SynchronizationContext.Send(state => graphicsDeviceManager.ApplyChanges(), null); + } +#endif + } + [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")] public override void SetPixel(int x, int y, uint color) { @@ -35,12 +47,6 @@ public override void SetPixel(int x, int y, uint color) public override void Update() // main thread { -#if WINDOWS - if (_game.GraphicsDeviceManager.IsFullScreen != IsFullScreen) - { - _game.GraphicsDeviceManager.ToggleFullScreen(); - } -#endif if (_pixelsDirty) { _pixelsDirty = false;