Cleaned up repository after conversion from Svn to Hg.

This commit is contained in:
Sean Fausett 2010-09-08 20:28:28 +12:00
parent 8d302f35e9
commit 01a1c1b1f5
8 changed files with 200 additions and 774 deletions

2
.hgignore Normal file
View File

@ -0,0 +1,2 @@
relre:/(bin|obj)/
relre:\.(cachefile|suo|user|vs10x)$

View File

@ -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' };
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -1,99 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Jellyfish.Virtu.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Resource &apos;{0}&apos; invalid..
/// </summary>
internal static string ResourceInvalid {
get {
return ResourceManager.GetString("ResourceInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Resource &apos;{0}&apos; not found..
/// </summary>
internal static string ResourceNotFound {
get {
return ResourceManager.GetString("ResourceNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Service type &apos;{0}&apos; already present..
/// </summary>
internal static string ServiceAlreadyPresent {
get {
return ResourceManager.GetString("ServiceAlreadyPresent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Service type &apos;{0}&apos; must be assignable from service provider &apos;{1}&apos;..
/// </summary>
internal static string ServiceMustBeAssignable {
get {
return ResourceManager.GetString("ServiceMustBeAssignable", resourceCulture);
}
}
}
}

View File

@ -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<Stream> 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<Stream> 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)
{
}
}
}
}

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.0">
<App xmlns="" ProductID="{89a50370-1ed9-4cf1-ad08-043b6e6f3c90}" Title="Virtu" RuntimeType="XNA" Version="1.0.0.0" Genre="Apps.Games" Author="" Description="" Publisher="">
<IconPath IsRelative="true" IsResource="false">AppThumbnail.png</IconPath>
<Capabilities>
<Capability Name="ID_CAP_NETWORKING" />
<Capability Name="ID_CAP_LOCATION" />
<Capability Name="ID_CAP_SENSORS" />
<Capability Name="ID_CAP_MICROPHONE" />
<Capability Name="ID_CAP_MEDIALIB" />
<Capability Name="ID_CAP_GAMERSERVICES" />
<Capability Name="ID_CAP_PHONEDIALER" />
<Capability Name="ID_CAP_PUSH_NOTIFICATION" />
<Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
</Capabilities>
<Tasks>
<DefaultTask Name="_default" PlaceHolderString="Default task" />
</Tasks>
<Tokens>
<PrimaryToken TokenID="Jellyfish.Virtu.Xna.Phone.Token" TaskName="_default">
<TemplateType5>
<BackgroundImageURI IsRelative="true" IsResource="false">AppThumbnail.png</BackgroundImageURI>
<Count>0</Count>
<Title>Virtu</Title>
</TemplateType5>
</PrimaryToken>
</Tokens>
</App>
</Deployment>