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;