Added support for 'Dos Order' (.do) disk images.

Added support for 'ProDos Order' (.po) disk images.
This commit is contained in:
Sean Fausett 2012-07-17 21:42:04 +12:00
parent 7aacc26962
commit c149a7260c
7 changed files with 78 additions and 29 deletions

View File

@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.RegularExpressions;
using Jellyfish.Library;
namespace Jellyfish.Virtu
@ -20,22 +21,19 @@ namespace Jellyfish.Virtu
{
throw new ArgumentNullException("name");
}
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase))
if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) ||
name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew
{
var data = new byte[TrackCount * SectorCount * SectorSize];
stream.ReadBlock(data);
return new DiskDsk(name, data, isWriteProtected);
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.Dos);
}
else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
{
var data = new byte[TrackCount * TrackSize];
stream.ReadBlock(data);
return new DiskNib(name, data, isWriteProtected);
return new DiskNib(name, stream, isWriteProtected);
}
else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
{
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.ProDos);
}
return null;
@ -50,17 +48,22 @@ namespace Jellyfish.Virtu
}
string name = reader.ReadString();
bool isWriteProtected = reader.ReadBoolean();
var data = reader.ReadBytes(reader.ReadInt32());
bool isWriteProtected = reader.ReadBoolean();
if (name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase))
if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) ||
name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew
{
return new DiskDsk(name, data, isWriteProtected);
return new DiskDsk(name, data, isWriteProtected, SectorSkew.Dos);
}
else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
{
return new DiskNib(name, data, isWriteProtected);
}
else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
{
return new DiskDsk(name, data, isWriteProtected, SectorSkew.ProDos);
}
return null;
}
@ -73,19 +76,18 @@ namespace Jellyfish.Virtu
}
writer.Write(Name);
writer.Write(IsWriteProtected);
writer.Write(Data.Length);
writer.Write(Data);
writer.Write(IsWriteProtected);
}
public abstract void ReadTrack(int number, int fraction, byte[] buffer);
public abstract void WriteTrack(int number, int fraction, byte[] buffer);
public string Name { get; private set; }
public bool IsWriteProtected { get; private set; }
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
protected byte[] Data { get; private set; }
public byte[] Data { get; protected set; }
public bool IsWriteProtected { get; private set; }
public const int SectorCount = 16;
public const int SectorSize = 0x100;

View File

@ -1,12 +1,29 @@
using System;
using System.IO;
using Jellyfish.Library;
namespace Jellyfish.Virtu
{
public sealed class DiskDsk : Disk525
public enum SectorSkew { None = 0, Dos, ProDos };
public class DiskDsk : Disk525
{
public DiskDsk(string name, byte[] data, bool isWriteProtected) :
public DiskDsk(string name, byte[] data, bool isWriteProtected, SectorSkew sectorSkew) :
base(name, data, isWriteProtected)
{
_sectorSkew = SectorSkewMode[(int)sectorSkew];
}
public DiskDsk(string name, Stream stream, bool isWriteProtected, SectorSkew sectorSkew) :
base(name, new byte[TrackCount * SectorCount * SectorSize], isWriteProtected)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
stream.ReadBlock(Data);
_sectorSkew = SectorSkewMode[(int)sectorSkew];
}
public override void ReadTrack(int number, int fraction, byte[] buffer)
@ -38,7 +55,7 @@ namespace Jellyfish.Virtu
WriteNibble(0xAA);
WriteNibble(0xAD);
WriteDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize);
WriteDataNibbles((track * SectorCount + _sectorSkew[sector]) * SectorSize);
WriteNibble(0xDE); // data epilogue
WriteNibble(0xAA);
@ -84,7 +101,7 @@ namespace Jellyfish.Virtu
if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20))
break; // no data prologue
if (!ReadDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize))
if (!ReadDataNibbles((track * SectorCount + _sectorSkew[sector]) * SectorSize))
break; // bad data checksum
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
@ -245,15 +262,33 @@ namespace Jellyfish.Virtu
private byte[] _primaryBuffer = new byte[0x100];
private const int SecondaryBufferLength = 0x56;
private byte[] _secondaryBuffer = new byte[SecondaryBufferLength + 1];
private int[] _sectorSkew;
private const int Volume = 0xFE;
private static readonly byte[] SwapBits = { 0, 2, 1, 3 };
private static readonly int[] DosOrderToLogicalSector = new int[]
private static readonly int[] SectorSkewNone = new int[SectorCount]
{
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
};
private static readonly int[] SectorSkewDos = new int[SectorCount]
{
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
};
private static readonly int[] SectorSkewProDos = new int[SectorCount]
{
0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF
};
private const int SectorSkewCount = 3;
private static readonly int[][] SectorSkewMode = new int[SectorSkewCount][]
{
SectorSkewNone, SectorSkewDos, SectorSkewProDos
};
private static readonly byte[] ByteToNibble = new byte[]
{
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,

View File

@ -1,4 +1,6 @@
using System;
using System.IO;
using Jellyfish.Library;
namespace Jellyfish.Virtu
{
@ -9,6 +11,17 @@ namespace Jellyfish.Virtu
{
}
public DiskNib(string name, Stream stream, bool isWriteProtected) :
base(name, new byte[TrackCount * TrackSize], isWriteProtected)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
stream.ReadBlock(Data);
}
public override void ReadTrack(int number, int fraction, byte[] buffer)
{
Buffer.BlockCopy(Data, (number / 2) * TrackSize, buffer, 0, TrackSize);

View File

@ -3,7 +3,6 @@ using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using Jellyfish.Virtu.Services;
@ -140,7 +139,7 @@ namespace Jellyfish.Virtu
{
loader(name, stream => Memory.LoadXex(stream));
}
else if (Regex.IsMatch(name, @"\.(dsk|nib)$", RegexOptions.IgnoreCase))
else
{
loader(name, stream => BootDiskII.BootDrive.InsertDisk(name, stream, false));
}
@ -231,7 +230,7 @@ namespace Jellyfish.Virtu
Uninitialize();
}
public const string Version = "0.9.2.0";
public const string Version = "0.9.3.0";
public MachineEvents Events { get; private set; }
public MachineServices Services { get; private set; }

View File

@ -65,7 +65,7 @@ namespace Jellyfish.Virtu
private void OnDiskButtonClick(int drive)
{
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.do;*.dsk;*.nib;*.po)|*.do;*.dsk;*.nib;*.po|All Files (*.*)|*.*" };
bool? result = dialog.ShowDialog();
if (result.HasValue && result.Value)
{

View File

@ -65,7 +65,7 @@ namespace Jellyfish.Virtu
//private void OnDiskButtonClick(int drive) // TODO
//{
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.do;*.dsk;*.nib;*.po)|*.do;*.dsk;*.nib;*.po|All Files (*.*)|*.*" };
// bool? result = dialog.ShowDialog();
// if (result.HasValue && result.Value)
// {

View File

@ -66,7 +66,7 @@ namespace Jellyfish.Virtu
private void OnDiskButtonClick(int drive)
{
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.do;*.dsk;*.nib;*.po)|*.do;*.dsk;*.nib;*.po|All Files (*.*)|*.*" };
bool? result = dialog.ShowDialog();
if (result.HasValue && result.Value)
{