diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..0a45a10 --- /dev/null +++ b/.hgignore @@ -0,0 +1,2 @@ +relre:/(bin|obj)/ +relre:\.(cachefile|suo|user|vs10x)$ diff --git a/Library/Xna/StringBuilderExtensions.cs b/Library/Xna/StringBuilderExtensions.cs deleted file mode 100644 index 48ecb7b..0000000 --- a/Library/Xna/StringBuilderExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Text; - -namespace Jellyfish.Library -{ - public static class StringBuilderExtensions - { - public static StringBuilder AppendWithoutGarbage(this StringBuilder builder, int number) - { - if (number < 0) - { - builder.Append('-'); - } - - int index = builder.Length; - do - { - builder.Insert(index, Digits, (number % 10) + 9, 1); - number /= 10; - } - while (number != 0); - - return builder; - } - - private static readonly char[] Digits = new char[] { '9', '8', '7', '6', '5', '4', '3', '2', '1', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; - } -} diff --git a/Virtu/DiskII.cs b/Virtu/DiskII.cs deleted file mode 100644 index 2b8fe9e..0000000 --- a/Virtu/DiskII.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Jellyfish.Virtu.Services; - -namespace Jellyfish.Virtu -{ - public sealed class DiskII : MachineComponent - { - public DiskII(Machine machine) : - base(machine) - { - } - - public override void Initialize() - { - _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 - } - - public override void Reset() - { - _phaseStates = 0; - SetMotorOn(false); - SetDriveNumber(0); - _loadMode = false; - _writeMode = false; - } - - public override void Uninitialize() - { - Flush(); - } - - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public int Read(int address) - { - switch (address & 0xF) - { - case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - SetPhase(address); - break; - - case 0x8: - SetMotorOn(false); - break; - - case 0x9: - SetMotorOn(true); - break; - - case 0xA: - SetDriveNumber(0); - break; - - case 0xB: - SetDriveNumber(1); - break; - - case 0xC: - _loadMode = false; - if (_motorOn) - { - if (!_writeMode) - { - return _latch = _drives[_driveNumber].Read(); - } - else - { - WriteLatch(); - } - } - break; - - case 0xD: - _loadMode = true; - if (_motorOn && !_writeMode) - { - // write protect is forced if phase 1 is on [F9.7] - _latch &= 0x7F; - if (_drives[_driveNumber].IsWriteProtected || - (_phaseStates & Phase1On) != 0) - { - _latch |= 0x80; - } - } - break; - - case 0xE: - _writeMode = false; - break; - - case 0xF: - _writeMode = true; - break; - } - - if ((address & 1) == 0) - { - // only even addresses return the latch - if (_motorOn) - { - return _latch; - } - - // simple hack to fool DOS SAMESLOT drive spin check (usually at $BD34) - _driveSpin = !_driveSpin; - return _driveSpin ? 0x7E : 0x7F; - } - - return Machine.Video.ReadFloatingBus(); // [5-40] - } - - public void Write(int address, int data) - { - switch (address & 0xF) - { - case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - SetPhase(address); - break; - - case 0x8: - SetMotorOn(false); - break; - - case 0x9: - SetMotorOn(true); - break; - - case 0xA: - SetDriveNumber(0); - break; - - case 0xB: - SetDriveNumber(1); - break; - - case 0xC: - _loadMode = false; - if (_writeMode) - { - WriteLatch(); - } - break; - - case 0xD: - _loadMode = true; - break; - - case 0xE: - _writeMode = false; - break; - - case 0xF: - _writeMode = true; - break; - } - - if (_motorOn && _writeMode) - { - if (_loadMode) - { - // any address writes latch for sequencer LD; OE1/2 irrelevant ['323 datasheet] - _latch = data; - } - } - } - - private void WriteLatch() - { - // write protect is forced if phase 1 is on [F9.7] - if ((_phaseStates & Phase1On) == 0) - { - _drives[_driveNumber].Write(_latch); - } - } - - private void Flush() - { - _drives[_driveNumber].FlushTrack(); - } - - private void SetDriveNumber(int driveNumber) - { - if (_driveNumber != driveNumber) - { - Flush(); - _driveNumber = driveNumber; - } - } - - private void SetMotorOn(bool state) - { - if (_motorOn && !state) - { - Flush(); - } - _motorOn = state; - } - - private void SetPhase(int address) - { - int phase = (address >> 1) & 0x3; - int state = address & 1; - _phaseStates &= ~(1 << phase); - _phaseStates |= (state << phase); - - if (_motorOn) - { - _drives[_driveNumber].ApplyPhaseChange(_phaseStates); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public Drive525[] Drives { get { return _drives; } } - - private const int Phase0On = 1 << 0; - private const int Phase1On = 1 << 1; - private const int Phase2On = 1 << 2; - private const int Phase3On = 1 << 3; - - private Drive525[] _drives = new Drive525[] { new Drive525(), new Drive525() }; - private int _latch; - private int _phaseStates; - private bool _motorOn; - private int _driveNumber; - private bool _loadMode; - private bool _writeMode; - private bool _driveSpin; - } -} diff --git a/Virtu/Drive525.cs b/Virtu/Drive525.cs deleted file mode 100644 index 8b50aa6..0000000 --- a/Virtu/Drive525.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.IO; -using System.Security; -using Jellyfish.Library; - -namespace Jellyfish.Virtu -{ - public sealed class Drive525 - { - public Drive525() - { - DriveArmStepDelta[0] = new int[] { 0, 0, 1, 1, 0, 0, 1, 1, -1, -1, 0, 0, -1, -1, 0, 0 }; // phase 0 - DriveArmStepDelta[1] = new int[] { 0, -1, 0, -1, 1, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0 }; // phase 1 - DriveArmStepDelta[2] = new int[] { 0, 0, -1, -1, 0, 0, -1, -1, 1, 1, 0, 0, 1, 1, 0, 0 }; // phase 2 - 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 InsertDisk(string fileName, bool isWriteProtected) - { - using (var stream = File.OpenRead(fileName)) - { - InsertDisk(fileName, stream, isWriteProtected); - } - } - - public void InsertDisk(string name, Stream stream, bool isWriteProtected) - { - FlushTrack(); - - // TODO handle null param/empty string for eject, or add Eject() - - _disk = Disk525.CreateDisk(name, stream.ReadAllBytes(), isWriteProtected); - _trackLoaded = false; - } - - public void ApplyPhaseChange(int phaseState) - { - // step the drive head according to stepper magnet changes - int delta = DriveArmStepDelta[_trackNumber & 0x3][phaseState]; - if (delta != 0) - { - int newTrackNumber = MathHelpers.Clamp(_trackNumber + delta, 0, TrackNumberMax); - if (newTrackNumber != _trackNumber) - { - FlushTrack(); - _trackNumber = newTrackNumber; - _trackOffset = 0; - _trackLoaded = false; - } - } - } - - public int Read() - { - if (LoadTrack()) - { - int data = _trackData[_trackOffset++]; - if (_trackOffset >= Disk525.TrackSize) - { - _trackOffset = 0; - } - - return data; - } - - return _random.Next(0x01, 0xFF); - } - - public void Write(int data) - { - if (LoadTrack()) - { - _trackChanged = true; - _trackData[_trackOffset++] = (byte)data; - if (_trackOffset >= Disk525.TrackSize) - { - _trackOffset = 0; - } - } - } - - private bool LoadTrack() - { - if (!_trackLoaded && (_disk != null)) - { - _disk.ReadTrack(_trackNumber, 0, _trackData); - _trackLoaded = true; - } - - return _trackLoaded; - } - - public void FlushTrack() - { - if (_trackChanged) - { - _disk.WriteTrack(_trackNumber, 0, _trackData); - _trackChanged = false; - } - } - - public bool IsWriteProtected { get { return _disk.IsWriteProtected; } } - - private const int TrackNumberMax = 0x44; - - private const int PhaseCount = 4; - - private readonly int[][] DriveArmStepDelta = new int[PhaseCount][]; - - private Disk525 _disk; - private bool _trackLoaded; - private bool _trackChanged; - private int _trackNumber; - private int _trackOffset; - private byte[] _trackData = new byte[Disk525.TrackSize]; - - private Random _random = new Random(); - } -} diff --git a/Virtu/NoSlotClock.cs b/Virtu/NoSlotClock.cs index 99cb314..8f81490 100644 --- a/Virtu/NoSlotClock.cs +++ b/Virtu/NoSlotClock.cs @@ -1,198 +1,198 @@ -using System; -using System.Collections; - -namespace Jellyfish.Virtu -{ - public sealed class NoSlotClock - { - public NoSlotClock() - { - Reset(); - } - - public void Reset() - { - // SmartWatch reset - whether tied to system reset is component specific - _comparisonRegister.Reset(); - _clockRegisterEnabled = false; - _writeEnabled = true; - } - - public int Read(int address, int data) - { - // this may read or write the clock - if ((address & 0x4) != 0) - { - return ClockRead(data); - } - - ClockWrite(address); - return data; - } - - public void Write(int address) - { - // this may read or write the clock - if ((address & 0x4) != 0) - { - ClockRead(0); - } - else - { - ClockWrite(address); - } - } - - public int ClockRead(int data) - { - // for a ROM, A2 high = read, and data out (if any) is on D0 - if (!_clockRegisterEnabled) - { - _comparisonRegister.Reset(); - _writeEnabled = true; - return data; - } - - data = _clockRegister.ReadBit(data); - if (_clockRegister.NextBit()) - { - _clockRegisterEnabled = false; - } - return data; - } - - public void ClockWrite(int address) - { - // for a ROM, A2 low = write, and data in is on A0 - if (!_writeEnabled) - { - return; - } - - if (!_clockRegisterEnabled) - { - if ((_comparisonRegister.CompareBit(address))) - { - if (_comparisonRegister.NextBit()) - { - _clockRegisterEnabled = true; - PopulateClockRegister(); - } - } - else - { - // mismatch ignores further writes - _writeEnabled = false; - } - } - else if (_clockRegister.NextBit()) - { - // simulate writes, but our clock register is read-only - _clockRegisterEnabled = false; - } - } - - private void PopulateClockRegister() - { - // all values are in packed BCD format (4 bits per decimal digit) - var now = DateTime.Now; - - int centisecond = now.Millisecond / 10; // 00-99 - _clockRegister.WriteNibble(centisecond % 10); - _clockRegister.WriteNibble(centisecond / 10); - - int second = now.Second; // 00-59 - _clockRegister.WriteNibble(second % 10); - _clockRegister.WriteNibble(second / 10); - - int minute = now.Minute; // 00-59 - _clockRegister.WriteNibble(minute % 10); - _clockRegister.WriteNibble(minute / 10); - - int hour = now.Hour; // 01-23 - _clockRegister.WriteNibble(hour % 10); - _clockRegister.WriteNibble(hour / 10); - - int day = (int)now.DayOfWeek + 1; // 01-07 (1 = Sunday) - _clockRegister.WriteNibble(day % 10); - _clockRegister.WriteNibble(day / 10); - - int date = now.Day; // 01-31 - _clockRegister.WriteNibble(date % 10); - _clockRegister.WriteNibble(date / 10); - - int month = now.Month; // 01-12 - _clockRegister.WriteNibble(month % 10); - _clockRegister.WriteNibble(month / 10); - - int year = now.Year % 100; // 00-99 - _clockRegister.WriteNibble(year % 10); - _clockRegister.WriteNibble(year / 10); - } - - private const ulong ClockInitSequence = 0x5CA33AC55CA33AC5; - - private bool _clockRegisterEnabled; - private bool _writeEnabled; - private RingRegister _clockRegister = new RingRegister(); - private RingRegister _comparisonRegister = new RingRegister(ClockInitSequence); - - private sealed class RingRegister - { - public RingRegister(ulong data = 0) - { - _register = data; - - Reset(); - } - - public void Reset() - { - _mask = 0x1; - } - - public void WriteNibble(int data) - { - WriteBits(data, 4); - } - - public void WriteBits(int data, int count) - { - for (int i = 1; i <= count; i++) - { - WriteBit(data); - NextBit(); - data >>= 1; - } - } - - public void WriteBit(int data) - { - _register = ((data & 0x1) != 0) ? (_register | _mask) : (_register & ~_mask); - } - - public int ReadBit(int data) - { - return ((_register & _mask) != 0) ? (data | 0x1) : (data & ~0x1); - } - - public bool CompareBit(int data) - { - return (((_register & _mask) != 0) == ((data & 0x1) != 0)); - } - - public bool NextBit() - { - if ((_mask <<= 1) == 0) - { - _mask = 0x1; - return true; // wrap - } - return false; - } - - private ulong _mask; - private ulong _register; - } - } -} +using System; +using System.Collections; + +namespace Jellyfish.Virtu +{ + public sealed class NoSlotClock + { + public NoSlotClock() + { + Reset(); + } + + public void Reset() + { + // SmartWatch reset - whether tied to system reset is component specific + _comparisonRegister.Reset(); + _clockRegisterEnabled = false; + _writeEnabled = true; + } + + public int Read(int address, int data) + { + // this may read or write the clock + if ((address & 0x4) != 0) + { + return ClockRead(data); + } + + ClockWrite(address); + return data; + } + + public void Write(int address) + { + // this may read or write the clock + if ((address & 0x4) != 0) + { + ClockRead(0); + } + else + { + ClockWrite(address); + } + } + + public int ClockRead(int data) + { + // for a ROM, A2 high = read, and data out (if any) is on D0 + if (!_clockRegisterEnabled) + { + _comparisonRegister.Reset(); + _writeEnabled = true; + return data; + } + + data = _clockRegister.ReadBit(data); + if (_clockRegister.NextBit()) + { + _clockRegisterEnabled = false; + } + return data; + } + + public void ClockWrite(int address) + { + // for a ROM, A2 low = write, and data in is on A0 + if (!_writeEnabled) + { + return; + } + + if (!_clockRegisterEnabled) + { + if ((_comparisonRegister.CompareBit(address))) + { + if (_comparisonRegister.NextBit()) + { + _clockRegisterEnabled = true; + PopulateClockRegister(); + } + } + else + { + // mismatch ignores further writes + _writeEnabled = false; + } + } + else if (_clockRegister.NextBit()) + { + // simulate writes, but our clock register is read-only + _clockRegisterEnabled = false; + } + } + + private void PopulateClockRegister() + { + // all values are in packed BCD format (4 bits per decimal digit) + var now = DateTime.Now; + + int centisecond = now.Millisecond / 10; // 00-99 + _clockRegister.WriteNibble(centisecond % 10); + _clockRegister.WriteNibble(centisecond / 10); + + int second = now.Second; // 00-59 + _clockRegister.WriteNibble(second % 10); + _clockRegister.WriteNibble(second / 10); + + int minute = now.Minute; // 00-59 + _clockRegister.WriteNibble(minute % 10); + _clockRegister.WriteNibble(minute / 10); + + int hour = now.Hour; // 01-23 + _clockRegister.WriteNibble(hour % 10); + _clockRegister.WriteNibble(hour / 10); + + int day = (int)now.DayOfWeek + 1; // 01-07 (1 = Sunday) + _clockRegister.WriteNibble(day % 10); + _clockRegister.WriteNibble(day / 10); + + int date = now.Day; // 01-31 + _clockRegister.WriteNibble(date % 10); + _clockRegister.WriteNibble(date / 10); + + int month = now.Month; // 01-12 + _clockRegister.WriteNibble(month % 10); + _clockRegister.WriteNibble(month / 10); + + int year = now.Year % 100; // 00-99 + _clockRegister.WriteNibble(year % 10); + _clockRegister.WriteNibble(year / 10); + } + + private const ulong ClockInitSequence = 0x5CA33AC55CA33AC5; + + private bool _clockRegisterEnabled; + private bool _writeEnabled; + private RingRegister _clockRegister = new RingRegister(); + private RingRegister _comparisonRegister = new RingRegister(ClockInitSequence); + + private sealed class RingRegister + { + public RingRegister(ulong data = 0) + { + _register = data; + + Reset(); + } + + public void Reset() + { + _mask = 0x1; + } + + public void WriteNibble(int data) + { + WriteBits(data, 4); + } + + public void WriteBits(int data, int count) + { + for (int i = 1; i <= count; i++) + { + WriteBit(data); + NextBit(); + data >>= 1; + } + } + + public void WriteBit(int data) + { + _register = ((data & 0x1) != 0) ? (_register | _mask) : (_register & ~_mask); + } + + public int ReadBit(int data) + { + return ((_register & _mask) != 0) ? (data | 0x1) : (data & ~0x1); + } + + public bool CompareBit(int data) + { + return (((_register & _mask) != 0) == ((data & 0x1) != 0)); + } + + public bool NextBit() + { + if ((_mask <<= 1) == 0) + { + _mask = 0x1; + return true; // wrap + } + return false; + } + + private ulong _mask; + private ulong _register; + } + } +} diff --git a/Virtu/Properties/SR.Designer.cs b/Virtu/Properties/SR.Designer.cs deleted file mode 100644 index e63de99..0000000 --- a/Virtu/Properties/SR.Designer.cs +++ /dev/null @@ -1,99 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Jellyfish.Virtu.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class SR { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal SR() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Jellyfish.Virtu.Properties.SR", typeof(SR).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Resource '{0}' invalid.. - /// - internal static string ResourceInvalid { - get { - return ResourceManager.GetString("ResourceInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Resource '{0}' not found.. - /// - internal static string ResourceNotFound { - get { - return ResourceManager.GetString("ResourceNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Service type '{0}' already present.. - /// - internal static string ServiceAlreadyPresent { - get { - return ResourceManager.GetString("ServiceAlreadyPresent", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Service type '{0}' must be assignable from service provider '{1}'.. - /// - internal static string ServiceMustBeAssignable { - get { - return ResourceManager.GetString("ServiceMustBeAssignable", resourceCulture); - } - } - } -} diff --git a/Virtu/Silverlight/Services/SilverlightStorageService.cs b/Virtu/Silverlight/Services/SilverlightStorageService.cs deleted file mode 100644 index 11a3ea2..0000000 --- a/Virtu/Silverlight/Services/SilverlightStorageService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; -using System.IO.IsolatedStorage; - -namespace Jellyfish.Virtu.Services -{ - public sealed class SilverlightStorageService : StorageService - { - public SilverlightStorageService(Machine machine) : - base(machine) - { - } - - public override void Load(string path, Action reader) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - try - { - using (var store = IsolatedStorageFile.GetUserStoreForApplication()) - { - using (var stream = new IsolatedStorageFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, store)) - { - reader(stream); - } - } - } - catch (FileNotFoundException) - { - } - catch (IsolatedStorageException) - { - } - } - - public override void Save(string path, Action writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - try - { - using (var store = IsolatedStorageFile.GetUserStoreForApplication()) - { - using (var stream = new IsolatedStorageFileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, store)) - { - writer(stream); - } - } - } - catch (IsolatedStorageException) - { - } - } - } -} diff --git a/Virtu/Xna/Properties/WindowsPhoneManifest.xml b/Virtu/Xna/Properties/WindowsPhoneManifest.xml deleted file mode 100644 index 2c1c504..0000000 --- a/Virtu/Xna/Properties/WindowsPhoneManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - AppThumbnail.png - - - - - - - - - - - - - - - - - - AppThumbnail.png - 0 - Virtu - - - - -