Added support for 'executable' (.xex) files.

Added 'default' debug service using Trace output.
Added more debug service logging to machine.
This commit is contained in:
Sean Fausett 2012-07-08 16:18:07 +12:00
parent b24bcd767e
commit 7aacc26962
20 changed files with 351 additions and 134 deletions

View File

@ -163,7 +163,7 @@ namespace Jellyfish.Library
private IntPtr _window;
private IDirectSound _device;
private IDirectSoundBuffer _buffer;
private object _bufferLock = new object();
private readonly object _bufferLock = new object();
private Action<IntPtr, int> _updater;
private AutoResetEvent _position1Event = new AutoResetEvent(false);

View File

@ -1,5 +1,4 @@
using System;
using System.Threading;
namespace Jellyfish.Library
{
@ -16,13 +15,11 @@ namespace Jellyfish.Library
{
if (_value == null)
{
T value = _initializer();
if (Interlocked.CompareExchange(ref _value, value, null) != null)
lock (_lock)
{
var disposable = value as IDisposable; // dispose preempted instance
if (disposable != null)
if (_value == null)
{
disposable.Dispose();
_value = _initializer();
}
}
}
@ -32,6 +29,7 @@ namespace Jellyfish.Library
}
private Func<T> _initializer;
private T _value;
private readonly object _lock = new object();
private volatile T _value;
}
}

View File

@ -6,13 +6,16 @@ namespace Jellyfish.Library
{
public static class StreamExtensions
{
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static int ReadBlock(this Stream stream, byte[] buffer, int offset = 0, int minCount = int.MaxValue)
[SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "3#")]
public static int ReadBlock(this Stream stream, byte[] buffer, int offset, ref int count)
{
return ReadBlock(stream, buffer, offset, int.MaxValue, minCount);
int read = ReadBlock(stream, buffer, offset, count, count);
count -= read;
return read;
}
public static int ReadBlock(this Stream stream, byte[] buffer, int offset, int count, int minCount)
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static int ReadBlock(this Stream stream, byte[] buffer, int offset = 0, int count = int.MaxValue, int minCount = int.MaxValue)
{
if (stream == null)
{
@ -42,6 +45,25 @@ namespace Jellyfish.Library
return total;
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static int ReadWord(this Stream stream, bool optional = false)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
int lowByte = stream.ReadByte();
int highByte = stream.ReadByte();
int word = lowByte | (highByte << 8);
if ((word < 0) && !optional)
{
throw new EndOfStreamException();
}
return word;
}
public static void SkipBlock(this Stream stream, int count)
{
if (stream == null)
@ -55,16 +77,18 @@ namespace Jellyfish.Library
}
else
{
const int BufferSize = 1024;
var buffer = new byte[BufferSize];
int total = 0;
int read;
do
{
total += read = stream.Read(buffer, 0, Math.Min(count - total, BufferSize));
total += read = stream.Read(_skipBuffer, 0, Math.Min(count - total, SkipBufferSize));
}
while ((read > 0) && (total < count));
}
}
private const int SkipBufferSize = 1024;
private static byte[] _skipBuffer = new byte[SkipBufferSize];
}
}

View File

@ -10,8 +10,10 @@
<Recognized>
<Word>Annunciator</Word>
<Word>Dsk</Word>
<Word>Prg</Word>
<Word>Unpause</Word>
<Word>Virtu</Word>
<Word>Xex</Word>
<Word>Xna</Word>
<Word>x</Word>
<Word>y</Word>

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Jellyfish.Library;
@ -11,6 +12,12 @@ namespace Jellyfish.Virtu
public DiskIIController(Machine machine) :
base(machine)
{
Drive1 = new DiskIIDrive(machine);
Drive2 = new DiskIIDrive(machine);
Drives = new Collection<DiskIIDrive> { Drive1, Drive2 };
BootDrive = Drive1;
}
public override void Initialize()
@ -41,7 +48,12 @@ namespace Jellyfish.Virtu
_loadMode = reader.ReadBoolean();
_writeMode = reader.ReadBoolean();
_driveSpin = reader.ReadBoolean();
_drives.ForEach(drive => drive.LoadState(reader, version));
foreach (var drive in Drives)
{
DebugService.WriteMessage("Loading machine '{0}'", drive.GetType().Name);
drive.LoadState(reader, version);
//DebugService.WriteMessage("Loaded machine '{0}'", drive.GetType().Name);
}
}
public override void SaveState(BinaryWriter writer)
@ -58,7 +70,12 @@ namespace Jellyfish.Virtu
writer.Write(_loadMode);
writer.Write(_writeMode);
writer.Write(_driveSpin);
_drives.ForEach(drive => drive.SaveState(writer));
foreach (var drive in Drives)
{
DebugService.WriteMessage("Saving machine '{0}'", drive.GetType().Name);
drive.SaveState(writer);
//DebugService.WriteMessage("Saved machine '{0}'", drive.GetType().Name);
}
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
@ -92,7 +109,7 @@ namespace Jellyfish.Virtu
{
if (!_writeMode)
{
return _latch = _drives[_driveNumber].Read();
return _latch = Drives[_driveNumber].Read();
}
else
{
@ -107,7 +124,7 @@ namespace Jellyfish.Virtu
{
// write protect is forced if phase 1 is on [F9.7]
_latch &= 0x7F;
if (_drives[_driveNumber].IsWriteProtected ||
if (Drives[_driveNumber].IsWriteProtected ||
(_phaseStates & Phase1On) != 0)
{
_latch |= 0x80;
@ -205,13 +222,13 @@ namespace Jellyfish.Virtu
// write protect is forced if phase 1 is on [F9.7]
if ((_phaseStates & Phase1On) == 0)
{
_drives[_driveNumber].Write(_latch);
Drives[_driveNumber].Write(_latch);
}
}
private void Flush()
{
_drives[_driveNumber].FlushTrack();
Drives[_driveNumber].FlushTrack();
}
private void SetDriveNumber(int driveNumber)
@ -241,19 +258,22 @@ namespace Jellyfish.Virtu
if (_motorOn)
{
_drives[_driveNumber].ApplyPhaseChange(_phaseStates);
Drives[_driveNumber].ApplyPhaseChange(_phaseStates);
}
}
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public DiskIIDrive[] Drives { get { return _drives; } }
public DiskIIDrive Drive1 { get; private set; }
public DiskIIDrive Drive2 { get; private set; }
public Collection<DiskIIDrive> Drives { get; private set; }
public DiskIIDrive BootDrive { get; private set; }
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 DiskIIDrive[] _drives = new DiskIIDrive[] { new DiskIIDrive(), new DiskIIDrive() };
private int _latch;
private int _phaseStates;
private bool _motorOn;

View File

@ -5,9 +5,10 @@ using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
{
public sealed class DiskIIDrive
public sealed class DiskIIDrive : MachineComponent
{
public DiskIIDrive()
public DiskIIDrive(Machine machine) :
base(machine)
{
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
@ -15,7 +16,7 @@ namespace Jellyfish.Virtu
DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3
}
public void LoadState(BinaryReader reader, Version version)
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
@ -30,10 +31,18 @@ namespace Jellyfish.Virtu
{
reader.Read(_trackData, 0, _trackData.Length);
}
_disk = reader.ReadBoolean() ? Disk525.LoadState(reader, version) : null;
if (reader.ReadBoolean())
{
DebugService.WriteMessage("Loading machine '{0}'", typeof(Disk525).Name);
_disk = Disk525.LoadState(reader, version);
}
else
{
_disk = null;
}
}
public void SaveState(BinaryWriter writer)
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
@ -51,12 +60,14 @@ namespace Jellyfish.Virtu
writer.Write(_disk != null);
if (_disk != null)
{
DebugService.WriteMessage("Saving machine '{0}'", _disk.GetType().Name);
_disk.SaveState(writer);
}
}
public void InsertDisk(string name, Stream stream, bool isWriteProtected)
{
DebugService.WriteMessage("Inserting disk '{0}'", name);
FlushTrack();
_disk = Disk525.CreateDisk(name, stream, isWriteProtected);
_trackLoaded = false;
@ -64,11 +75,15 @@ namespace Jellyfish.Virtu
public void RemoveDisk()
{
_trackLoaded = false;
_trackChanged = false;
_trackNumber = 0;
_trackOffset = 0;
_disk = null;
if (_disk != null)
{
DebugService.WriteMessage("Removing disk '{0}'", _disk.Name);
_trackLoaded = false;
_trackChanged = false;
_trackNumber = 0;
_trackOffset = 0;
_disk = null;
}
}
public void ApplyPhaseChange(int phaseState)

View File

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -39,6 +39,8 @@ namespace Jellyfish.Virtu
Slots = new Collection<PeripheralCard> { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
Components = new Collection<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
BootDiskII = Slots.OfType<DiskIIController>().Last();
Thread = new Thread(Run) { Name = "Machine" };
}
@ -52,33 +54,45 @@ namespace Jellyfish.Virtu
{
foreach (var component in Components)
{
//_debugService.WriteLine("Resetting component '{0}'", component.GetType().Name);
_debugService.WriteMessage("Resetting machine '{0}'", component.GetType().Name);
component.Reset();
//_debugService.WriteLine("Reset component '{0}'", component.GetType().Name);
//_debugService.WriteMessage("Reset machine '{0}'", component.GetType().Name);
}
}
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
public void Start()
{
_debugService = Services.GetService<DebugService>();
_storageService = Services.GetService<StorageService>();
_debugService.WriteMessage("Starting machine");
State = MachineState.Starting;
Thread.Start();
}
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
public void Pause()
{
_debugService.WriteMessage("Pausing machine");
State = MachineState.Pausing;
_pauseEvent.WaitOne();
State = MachineState.Paused;
_debugService.WriteMessage("Paused machine");
}
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
public void Unpause()
{
_debugService.WriteMessage("Running machine");
State = MachineState.Running;
_unpauseEvent.Set();
}
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
public void Stop()
{
_debugService.WriteMessage("Stopping machine");
State = MachineState.Stopping;
_unpauseEvent.Set();
if (Thread.IsAlive)
@ -86,15 +100,16 @@ namespace Jellyfish.Virtu
Thread.Join();
}
State = MachineState.Stopped;
_debugService.WriteMessage("Stopped machine");
}
private void Initialize()
{
foreach (var component in Components)
{
//_debugService.WriteLine("Initializing component '{0}'", component.GetType().Name);
_debugService.WriteMessage("Initializing machine '{0}'", component.GetType().Name);
component.Initialize();
//_debugService.WriteLine("Initialized component '{0}'", component.GetType().Name);
//_debugService.WriteMessage("Initialized machine '{0}'", component.GetType().Name);
}
}
@ -119,18 +134,22 @@ namespace Jellyfish.Virtu
}
else if (name.EndsWith(".prg", StringComparison.OrdinalIgnoreCase))
{
loader(name, stream => Memory.LoadProgram(stream));
loader(name, stream => Memory.LoadPrg(stream));
}
else if (name.EndsWith(".xex", StringComparison.OrdinalIgnoreCase))
{
loader(name, stream => Memory.LoadXex(stream));
}
else if (Regex.IsMatch(name, @"\.(dsk|nib)$", RegexOptions.IgnoreCase))
{
loader(name, stream => BootDiskII.Drives[0].InsertDisk(name, stream, false));
loader(name, stream => BootDiskII.BootDrive.InsertDisk(name, stream, false));
}
}
else
#endif
if (!_storageService.Load(Machine.StateFileName, stream => LoadState(stream)))
{
StorageService.LoadResource("Disks/Default.dsk", stream => BootDiskII.Drives[0].InsertDisk("Default.dsk", stream, false));
StorageService.LoadResource("Disks/Default.dsk", stream => BootDiskII.BootDrive.InsertDisk("Default.dsk", stream, false));
}
}
@ -138,17 +157,17 @@ namespace Jellyfish.Virtu
{
using (var reader = new BinaryReader(stream))
{
string stateSignature = reader.ReadString();
var stateVersion = new Version(reader.ReadString());
if ((stateSignature != StateSignature) || (stateVersion != new Version(Machine.Version))) // avoid state version mismatch (for now)
string signature = reader.ReadString();
var version = new Version(reader.ReadString());
if ((signature != StateSignature) || (version != new Version(Machine.Version))) // avoid state version mismatch (for now)
{
throw new InvalidOperationException();
}
foreach (var component in Components)
{
//_debugService.WriteLine("Loading component '{0}' state", component.GetType().Name);
component.LoadState(reader, stateVersion);
//_debugService.WriteLine("Loaded component '{0}' state", component.GetType().Name);
_debugService.WriteMessage("Loading machine '{0}'", component.GetType().Name);
component.LoadState(reader, version);
//_debugService.WriteMessage("Loaded machine '{0}'", component.GetType().Name);
}
}
}
@ -166,9 +185,9 @@ namespace Jellyfish.Virtu
writer.Write(Machine.Version);
foreach (var component in Components)
{
//_debugService.WriteLine("Saving component '{0}' state", component.GetType().Name);
_debugService.WriteMessage("Saving machine '{0}'", component.GetType().Name);
component.SaveState(writer);
//_debugService.WriteLine("Saved component '{0}' state", component.GetType().Name);
//_debugService.WriteMessage("Saved machine '{0}'", component.GetType().Name);
}
}
}
@ -177,22 +196,20 @@ namespace Jellyfish.Virtu
{
foreach (var component in Components)
{
//_debugService.WriteLine("Uninitializing component '{0}'", component.GetType().Name);
_debugService.WriteMessage("Uninitializing machine '{0}'", component.GetType().Name);
component.Uninitialize();
//_debugService.WriteLine("Uninitialized component '{0}'", component.GetType().Name);
//_debugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name);
}
}
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
private void Run() // machine thread
{
//_debugService = Services.GetService<DebugService>();
_storageService = Services.GetService<StorageService>();
_bootDiskII = Slots.OfType<DiskIIController>().Last();
Initialize();
Reset();
LoadState();
_debugService.WriteMessage("Running machine");
State = MachineState.Running;
do
{
@ -237,20 +254,19 @@ namespace Jellyfish.Virtu
public PeripheralCard Slot6 { get; private set; }
public PeripheralCard Slot7 { get; private set; }
public DiskIIController BootDiskII { get { return _bootDiskII; } }
public Collection<PeripheralCard> Slots { get; private set; }
public Collection<MachineComponent> Components { get; private set; }
public DiskIIController BootDiskII { get; private set; }
public Thread Thread { get; private set; }
private const string StateFileName = "State.bin";
private const string StateSignature = "Virtu";
//private DebugService _debugService;
private DebugService _debugService;
private StorageService _storageService;
private volatile MachineState _state;
private DiskIIController _bootDiskII;
private AutoResetEvent _pauseEvent = new AutoResetEvent(false);
private AutoResetEvent _unpauseEvent = new AutoResetEvent(false);

View File

@ -1,5 +1,7 @@
using System;
using System.IO;
using Jellyfish.Library;
using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
{
@ -8,6 +10,8 @@ namespace Jellyfish.Virtu
protected MachineComponent(Machine machine)
{
Machine = machine;
_debugService = new Lazy<DebugService>(() => Machine.Services.GetService<DebugService>());
}
public virtual void Initialize()
@ -31,5 +35,8 @@ namespace Jellyfish.Virtu
}
protected Machine Machine { get; private set; }
protected DebugService DebugService { get { return _debugService.Value; } }
private Lazy<DebugService> _debugService;
}
}

View File

@ -1,7 +1,9 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using Jellyfish.Library;
using Jellyfish.Virtu.Properties;
using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
@ -124,45 +126,6 @@ namespace Jellyfish.Virtu
MapRegionD0FF();
}
public void LoadProgram(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
int address = stream.ReadByte();
address |= stream.ReadByte() << 8;
if (address < 0)
{
throw new EndOfStreamException();
}
int entry = address;
if (address < 0x0200)
{
address += stream.ReadBlock(_ramMainRegion0001, address, 0);
}
if ((0x0200 <= address) && (address < 0xC000))
{
address += stream.ReadBlock(_ramMainRegion02BF, address - 0x0200, 0);
}
if ((0xC000 <= address) && (address < 0xD000))
{
address += stream.ReadBlock(_ramMainBank1RegionD0DF, address - 0xC000, 0);
}
if ((0xD000 <= address) && (address < 0xE000))
{
address += stream.ReadBlock(_ramMainBank2RegionD0DF, address - 0xD000, 0);
}
if (0xE000 <= address)
{
address += stream.ReadBlock(_ramMainRegionE0FF, address - 0xE000, 0);
}
SetWarmEntry(entry); // assumes autostart monitor
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
@ -212,6 +175,49 @@ namespace Jellyfish.Virtu
writer.Write(_ramAuxRegionE0FF);
}
public void LoadPrg(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
int startAddress = stream.ReadWord();
SetWarmEntry(startAddress); // assumes autostart monitor
Load(stream, startAddress);
}
public void LoadXex(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
const int Marker = 0xFFFF;
int marker = stream.ReadWord(); // mandatory marker
if (marker != Marker)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Strings.MarkerNotFound, Marker));
}
int startAddress = stream.ReadWord();
int endAddress = stream.ReadWord();
SetWarmEntry(startAddress); // assumes autostart monitor
do
{
if (startAddress > endAddress)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Strings.InvalidAddressRange, startAddress, endAddress));
}
Load(stream, startAddress, endAddress - startAddress + 1);
marker = stream.ReadWord(optional: true); // optional marker
startAddress = (marker != Marker) ? marker : stream.ReadWord(optional: true);
endAddress = stream.ReadWord(optional: true);
}
while ((startAddress >= 0) && (endAddress >= 0));
}
#region Core Read & Write
public int Read(int address)
{
@ -1546,6 +1552,62 @@ namespace Jellyfish.Virtu
}
#endregion
private void Load(Stream stream, int startAddress)
{
DebugService.WriteMessage("Loading memory ${0:X04}", startAddress);
int address = startAddress;
if (address < 0x0200)
{
address += stream.ReadBlock(_ramMainRegion0001, address, minCount: 0);
}
if ((0x0200 <= address) && (address < 0xC000))
{
address += stream.ReadBlock(_ramMainRegion02BF, address - 0x0200, minCount: 0);
}
if ((0xC000 <= address) && (address < 0xD000))
{
address += stream.ReadBlock(_ramMainBank1RegionD0DF, address - 0xC000, minCount: 0);
}
if ((0xD000 <= address) && (address < 0xE000))
{
address += stream.ReadBlock(_ramMainBank2RegionD0DF, address - 0xD000, minCount: 0);
}
if (0xE000 <= address)
{
address += stream.ReadBlock(_ramMainRegionE0FF, address - 0xE000, minCount: 0);
}
if (address > startAddress)
{
DebugService.WriteMessage("Loaded memory ${0:X04}-${1:X04} (${2:X04})", startAddress, address - 1, address - startAddress);
}
}
private void Load(Stream stream, int startAddress, int length)
{
DebugService.WriteMessage("Loading memory ${0:X04}-${1:X04} (${2:X04})", startAddress, startAddress + length - 1, length);
int address = startAddress;
if (address < 0x0200)
{
address += stream.ReadBlock(_ramMainRegion0001, address, ref length);
}
if ((0x0200 <= address) && (address < 0xC000))
{
address += stream.ReadBlock(_ramMainRegion02BF, address - 0x0200, ref length);
}
if ((0xC000 <= address) && (address < 0xD000))
{
address += stream.ReadBlock(_ramMainBank1RegionD0DF, address - 0xC000, ref length);
}
if ((0xD000 <= address) && (address < 0xE000))
{
address += stream.ReadBlock(_ramMainBank2RegionD0DF, address - 0xD000, ref length);
}
if (0xE000 <= address)
{
address += stream.ReadBlock(_ramMainRegionE0FF, address - 0xE000, ref length);
}
}
private void SetWarmEntry(int address)
{
_ramMainRegion02BF[0x03F2 - 0x0200] = (byte)(address & 0xFF);

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.530
// Runtime Version:4.0.30319.544
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -60,6 +60,24 @@ namespace Jellyfish.Virtu.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Invalid address range ${0:X04}-${1:X04}..
/// </summary>
internal static string InvalidAddressRange {
get {
return ResourceManager.GetString("InvalidAddressRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Marker ${0:X04} not found..
/// </summary>
internal static string MarkerNotFound {
get {
return ResourceManager.GetString("MarkerNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Resource &apos;{0}&apos; not found..
/// </summary>

View File

@ -117,6 +117,12 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="InvalidAddressRange" xml:space="preserve">
<value>Invalid address range ${0:X04}-${1:X04}.</value>
</data>
<data name="MarkerNotFound" xml:space="preserve">
<value>Marker ${0:X04} not found.</value>
</data>
<data name="ResourceNotFound" xml:space="preserve">
<value>Resource '{0}' not found.</value>
</data>

View File

@ -1,6 +1,9 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;
using Jellyfish.Library;
namespace Jellyfish.Virtu.Services
{
@ -11,19 +14,54 @@ namespace Jellyfish.Virtu.Services
{
}
public void WriteLine(string message)
public void WriteMessage(string message)
{
OnWriteLine(string.Concat(DateTime.Now.TimeOfDay, ' ', message));
OnWriteMessage(FormatMessage(message));
}
public void WriteLine(string format, params object[] args)
public void WriteMessage(string format, params object[] args)
{
WriteLine(string.Format(CultureInfo.InvariantCulture, format, args));
OnWriteMessage(FormatMessage(format, args));
}
protected virtual void OnWriteLine(string message)
protected virtual void OnWriteMessage(string message)
{
#if SILVERLIGHT || WINDOWS_PHONE || XBOX
Debug.WriteLine(message);
#else
Trace.WriteLine(message);
#endif
}
private string FormatMessage(string format, params object[] args)
{
var message = new StringBuilder(256);
message.AppendFormat(CultureInfo.InvariantCulture, "[{0} T{1:X3} Virtu] ", DateTime.Now.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture), Thread.CurrentThread.ManagedThreadId);
if (args.Length > 0)
{
try
{
message.AppendFormat(CultureInfo.InvariantCulture, format, args);
}
catch (FormatException ex)
{
#if WINDOWS_PHONE || XBOX
WriteMessage("[DebugService.FormatMessage] format: {0}; exception: {1}", format, ex.Message);
#else
WriteMessage("[DebugService.FormatMessage] format: {0}; args: {1}; exception: {2}", format, string.Join(", ", args), ex.Message);
#endif
}
}
else
{
message.Append(format);
}
return message.ToString();
}
public static DebugService Default { get { return _default.Value; } }
private static readonly Lazy<DebugService> _default = new Lazy<DebugService>(() => new DebugService(null));
}
}

View File

@ -20,11 +20,12 @@ namespace Jellyfish.Virtu.Services
{
try
{
DebugService.WriteMessage("Loading file '{0}'", fileName);
OnLoad(fileName, reader);
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.WriteMessage(ex.ToString());
return false;
}
@ -44,14 +45,15 @@ namespace Jellyfish.Virtu.Services
try
{
DebugService.Default.WriteMessage("Loading file '{0}'", fileName);
using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
reader(stream);
}
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.Default.WriteMessage(ex.ToString());
return false;
}
@ -75,14 +77,15 @@ namespace Jellyfish.Virtu.Services
try
{
DebugService.Default.WriteMessage("Loading file '{0}'", fileInfo.Name);
using (var stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
{
reader(stream);
}
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.Default.WriteMessage(ex.ToString());
return false;
}
@ -99,14 +102,15 @@ namespace Jellyfish.Virtu.Services
try
{
DebugService.Default.WriteMessage("Loading resource '{0}'", resourceName);
using (var stream = GetResourceStream(resourceName))
{
reader(stream);
}
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.Default.WriteMessage(ex.ToString());
return false;
}
@ -118,11 +122,12 @@ namespace Jellyfish.Virtu.Services
{
try
{
DebugService.WriteMessage("Saving file '{0}'", fileName);
OnSave(fileName, writer);
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.WriteMessage(ex.ToString());
return false;
}
@ -142,14 +147,15 @@ namespace Jellyfish.Virtu.Services
try
{
DebugService.Default.WriteMessage("Saving file '{0}'", fileName);
using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
writer(stream);
}
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.Default.WriteMessage(ex.ToString());
return false;
}
@ -173,14 +179,15 @@ namespace Jellyfish.Virtu.Services
try
{
DebugService.Default.WriteMessage("Saving file '{0}'", fileInfo.Name);
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write, FileShare.None))
{
writer(stream);
}
}
catch (Exception e)
catch (Exception ex)
{
Debug.WriteLine(e.ToString());
DebugService.Default.WriteMessage(ex.ToString());
return false;
}

View File

@ -15,7 +15,7 @@ namespace Jellyfish.Virtu
if (!DesignerProperties.IsInDesignTool)
{
_debugService = new SilverlightDebugService(_machine, this);
_debugService = DebugService.Default;
_storageService = new IsolatedStorageService(_machine);
_keyboardService = new SilverlightKeyboardService(_machine, this);
_gamePortService = new GamePortService(_machine); // not connected
@ -49,9 +49,9 @@ namespace Jellyfish.Virtu
_videoService.Dispose();
}
public void WriteLine(string message)
public void WriteMessage(string message)
{
_debugText.Text += message;
_debugText.Text += message + Environment.NewLine;
_debugScrollViewer.UpdateLayout();
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
}

View File

@ -15,7 +15,7 @@ namespace Jellyfish.Virtu
if (!DesignerProperties.IsInDesignTool)
{
_debugService = new SilverlightDebugService(_machine, this);
_debugService = DebugService.Default;
_storageService = new IsolatedStorageService(_machine);
_keyboardService = new SilverlightKeyboardService(_machine, this);
_gamePortService = new GamePortService(_machine); // not connected
@ -49,9 +49,9 @@ namespace Jellyfish.Virtu
_videoService.Dispose();
}
public void WriteLine(string message)
public void WriteMessage(string message)
{
_debugText.Text += message;
_debugText.Text += message + Environment.NewLine;
_debugScrollViewer.UpdateLayout();
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
}

View File

@ -16,9 +16,9 @@ namespace Jellyfish.Virtu.Services
_page = page;
}
protected override void OnWriteLine(string message)
protected override void OnWriteMessage(string message)
{
_page.Dispatcher.Post(() => _page.WriteLine(message + Environment.NewLine));
_page.Dispatcher.Post(() => _page.WriteMessage(message));
}
private MainPage _page;

View File

@ -29,6 +29,8 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
<NoWarn>
</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
@ -41,6 +43,8 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
<NoWarn>
</NoWarn>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Jellyfish.Virtu.MainApp</StartupObject>

View File

@ -16,7 +16,7 @@ namespace Jellyfish.Virtu
if (!DesignerProperties.GetIsInDesignMode(this))
{
_debugService = new WpfDebugService(_machine, this);
_debugService = DebugService.Default;
_storageService = new WpfStorageService(_machine);
_keyboardService = new WpfKeyboardService(_machine, this);
_gamePortService = new GamePortService(_machine); // not connected
@ -50,9 +50,9 @@ namespace Jellyfish.Virtu
_videoService.Dispose();
}
public void WriteLine(string message)
public void WriteMessage(string message)
{
_debugText.Text += message;
_debugText.Text += message + Environment.NewLine;
_debugScrollViewer.UpdateLayout();
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
}

View File

@ -16,9 +16,9 @@ namespace Jellyfish.Virtu.Services
_page = page;
}
protected override void OnWriteLine(string message)
protected override void OnWriteMessage(string message)
{
_page.Dispatcher.Post(() => _page.WriteLine(message + Environment.NewLine));
_page.Dispatcher.Post(() => _page.WriteMessage(message));
}
private MainPage _page;

View File

@ -20,7 +20,7 @@ namespace Jellyfish.Virtu
frameRateCounter.DrawOrder = 1;
frameRateCounter.FontName = "Consolas";
_debugService = new DebugService(_machine);
_debugService = DebugService.Default;
#if WINDOWS_PHONE
_storageService = new IsolatedStorageService(_machine);
#else