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;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Text.RegularExpressions;
using Jellyfish.Library; using Jellyfish.Library;
namespace Jellyfish.Virtu namespace Jellyfish.Virtu
@ -20,22 +21,19 @@ public static Disk525 CreateDisk(string name, Stream stream, bool isWriteProtect
{ {
throw new ArgumentNullException("name"); 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]; return new DiskDsk(name, stream, isWriteProtected, SectorSkew.Dos);
stream.ReadBlock(data);
return new DiskDsk(name, data, isWriteProtected);
} }
else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase)) else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
{ {
var data = new byte[TrackCount * TrackSize]; return new DiskNib(name, stream, isWriteProtected);
stream.ReadBlock(data); }
return new DiskNib(name, data, isWriteProtected); else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
{
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.ProDos);
} }
return null; return null;
@ -50,17 +48,22 @@ public static Disk525 LoadState(BinaryReader reader, Version version)
} }
string name = reader.ReadString(); string name = reader.ReadString();
bool isWriteProtected = reader.ReadBoolean();
var data = reader.ReadBytes(reader.ReadInt32()); 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)) else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
{ {
return new DiskNib(name, data, isWriteProtected); return new DiskNib(name, data, isWriteProtected);
} }
else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
{
return new DiskDsk(name, data, isWriteProtected, SectorSkew.ProDos);
}
return null; return null;
} }
@ -73,19 +76,18 @@ public void SaveState(BinaryWriter writer)
} }
writer.Write(Name); writer.Write(Name);
writer.Write(IsWriteProtected);
writer.Write(Data.Length); writer.Write(Data.Length);
writer.Write(Data); writer.Write(Data);
writer.Write(IsWriteProtected);
} }
public abstract void ReadTrack(int number, int fraction, byte[] buffer); public abstract void ReadTrack(int number, int fraction, byte[] buffer);
public abstract void WriteTrack(int number, int fraction, byte[] buffer); public abstract void WriteTrack(int number, int fraction, byte[] buffer);
public string Name { get; private set; } public string Name { get; private set; }
public bool IsWriteProtected { get; private set; }
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [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 SectorCount = 16;
public const int SectorSize = 0x100; public const int SectorSize = 0x100;

View File

@ -1,12 +1,29 @@
using System; using System;
using System.IO;
using Jellyfish.Library;
namespace Jellyfish.Virtu 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) 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) public override void ReadTrack(int number, int fraction, byte[] buffer)
@ -38,7 +55,7 @@ public override void ReadTrack(int number, int fraction, byte[] buffer)
WriteNibble(0xAA); WriteNibble(0xAA);
WriteNibble(0xAD); WriteNibble(0xAD);
WriteDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize); WriteDataNibbles((track * SectorCount + _sectorSkew[sector]) * SectorSize);
WriteNibble(0xDE); // data epilogue WriteNibble(0xDE); // data epilogue
WriteNibble(0xAA); WriteNibble(0xAA);
@ -84,7 +101,7 @@ public override void WriteTrack(int number, int fraction, byte[] buffer)
if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20)) if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20))
break; // no data prologue break; // no data prologue
if (!ReadDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize)) if (!ReadDataNibbles((track * SectorCount + _sectorSkew[sector]) * SectorSize))
break; // bad data checksum break; // bad data checksum
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA)) if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
@ -245,15 +262,33 @@ private void WriteDataNibbles(int sectorOffset)
private byte[] _primaryBuffer = new byte[0x100]; private byte[] _primaryBuffer = new byte[0x100];
private const int SecondaryBufferLength = 0x56; private const int SecondaryBufferLength = 0x56;
private byte[] _secondaryBuffer = new byte[SecondaryBufferLength + 1]; private byte[] _secondaryBuffer = new byte[SecondaryBufferLength + 1];
private int[] _sectorSkew;
private const int Volume = 0xFE; private const int Volume = 0xFE;
private static readonly byte[] SwapBits = { 0, 2, 1, 3 }; 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 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[] private static readonly byte[] ByteToNibble = new byte[]
{ {
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3, 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;
using System.IO;
using Jellyfish.Library;
namespace Jellyfish.Virtu namespace Jellyfish.Virtu
{ {
@ -9,6 +11,17 @@ public DiskNib(string name, byte[] data, bool isWriteProtected) :
{ {
} }
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) public override void ReadTrack(int number, int fraction, byte[] buffer)
{ {
Buffer.BlockCopy(Data, (number / 2) * TrackSize, buffer, 0, TrackSize); Buffer.BlockCopy(Data, (number / 2) * TrackSize, buffer, 0, TrackSize);

View File

@ -3,7 +3,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using Jellyfish.Virtu.Services; using Jellyfish.Virtu.Services;
@ -140,7 +139,7 @@ private void LoadState()
{ {
loader(name, stream => Memory.LoadXex(stream)); 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)); loader(name, stream => BootDiskII.BootDrive.InsertDisk(name, stream, false));
} }
@ -231,7 +230,7 @@ private void Run() // machine thread
Uninitialize(); Uninitialize();
} }
public const string Version = "0.9.2.0"; public const string Version = "0.9.3.0";
public MachineEvents Events { get; private set; } public MachineEvents Events { get; private set; }
public MachineServices Services { get; private set; } public MachineServices Services { get; private set; }

View File

@ -65,7 +65,7 @@ private void OnCompositionTargetRendering(object sender, EventArgs e)
private void OnDiskButtonClick(int drive) 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(); bool? result = dialog.ShowDialog();
if (result.HasValue && result.Value) if (result.HasValue && result.Value)
{ {

View File

@ -65,7 +65,7 @@ private void OnCompositionTargetRendering(object sender, EventArgs e)
//private void OnDiskButtonClick(int drive) // TODO //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(); // bool? result = dialog.ShowDialog();
// if (result.HasValue && result.Value) // if (result.HasValue && result.Value)
// { // {

View File

@ -66,7 +66,7 @@ private void OnCompositionTargetRendering(object sender, EventArgs e)
private void OnDiskButtonClick(int drive) 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(); bool? result = dialog.ShowDialog();
if (result.HasValue && result.Value) if (result.HasValue && result.Value)
{ {