Implemented writing for DSK and NIB images (in-memory only for now)

--HG--
extra : convert_revision : svn%3Affd33b8c-2492-42e0-bdc5-587b920b7d6d/trunk%4023513
This commit is contained in:
Nick Westgate 2009-07-02 01:22:35 +00:00
parent 541a0e9f83
commit 7522f7cd15
5 changed files with 175 additions and 20 deletions

View File

@ -9,7 +9,7 @@ namespace Jellyfish.Virtu
{ {
Name = name; Name = name;
Data = data; Data = data;
IsWriteProtected = true; // TODO use isWriteProtected IsWriteProtected = isWriteProtected;
} }
public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected) public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected)

View File

@ -49,8 +49,124 @@ namespace Jellyfish.Virtu
public override void WriteTrack(int number, int fraction, byte[] buffer) public override void WriteTrack(int number, int fraction, byte[] buffer)
{ {
// TODO if (IsWriteProtected)
throw new NotImplementedException(); return;
int track = number / 2;
_trackBuffer = buffer;
_trackOffset = 0;
int sectorsDone = 0;
for (int sector = 0; sector < SectorCount; sector++)
{
if (!Read3Nibbles(0xD5, 0xAA, 0x96, 0x304))
break; // no address prologue
int readVolume = ReadNibble44();
int readTrack = ReadNibble44();
if (readTrack != track)
break; // bad track number
int readSector = ReadNibble44();
if (readSector > SectorCount)
break; // bad sector number
if ((sectorsDone & (0x1 << readSector)) != 0)
break; // already done this sector
if (ReadNibble44() != (Volume ^ readTrack ^ readSector))
break; // bad address checksum
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
break; // bad address epilogue
if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20))
break; // no data prologue
if (ReadDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize) != 0)
break; // bad data checksum
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
break; // bad data epilogue
sectorsDone |= 0x1 << sector;
}
if (sectorsDone != 0xFFFF)
throw new Exception("disk error"); // TODO: not sure what we want here
}
private byte ReadNibble()
{
byte data = _trackBuffer[_trackOffset];
if (_trackOffset++ == TrackSize)
{
_trackOffset = 0;
}
return data;
}
private bool Read3Nibbles(byte data1, byte data2, byte data3, int maxReads)
{
bool result = false;
byte nibble;
while (--maxReads > 0)
{
if ((nibble = ReadNibble()) != data1)
continue;
if ((nibble = ReadNibble()) != data2)
continue;
if ((nibble = ReadNibble()) != data3)
continue;
result = true;
break;
}
return result;
}
private int ReadNibble44()
{
return (((ReadNibble() << 1) | 0x1) & ReadNibble());
}
private byte ReadDataNibbles(int sectorOffset)
{
byte a, x, y;
y = SecondaryBufferLength;
a = 0;
do // fill and de-nibblize secondary buffer
{
a = _secondaryBuffer[--y] = (byte)(a ^ NibbleToByte[ReadNibble()]);
}
while (y > 0);
do // fill and de-nibblize secondary buffer
{
a = _primaryBuffer[y++] = (byte)(a ^ NibbleToByte[ReadNibble()]);
}
while (y != 0);
byte checksum = NibbleToByte[ReadNibble()]; // should be 0
x = y = 0;
do // decode data
{
if (x == 0)
{
x = SecondaryBufferLength;
}
a = (byte)((_primaryBuffer[y] << 2) | SwapBits[_secondaryBuffer[--x] & 0x03]);
_secondaryBuffer[x] >>= 2;
Data[sectorOffset + y] = a;
}
while (++y != 0);
return checksum;
} }
private void WriteNibble(int data) private void WriteNibble(int data)
@ -134,5 +250,29 @@ namespace Jellyfish.Virtu
0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
}; };
private static readonly byte[] NibbleToByte = new byte[]
{
// padding for offset (not used)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
// nibble translate table
0x00, 0x01, 0x98, 0x99, 0x02, 0x03, 0x9C, 0x04, 0x05, 0x06,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x07, 0x08, 0xA8, 0xA9, 0xAA, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0xB0, 0xB1, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xB8, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x1B, 0xCC, 0x1C, 0x1D, 0x1E,
0xD0, 0xD1, 0xD2, 0x1F, 0xD4, 0xD5, 0x20, 0x21, 0xD8, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x29, 0x2A, 0x2B, 0xE8, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
0xF0, 0xF1, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0xF8, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
};
} }
} }

View File

@ -75,9 +75,16 @@ namespace Jellyfish.Virtu
case 0xC: case 0xC:
_loadMode = false; _loadMode = false;
if (_motorOn && !_writeMode) if (_motorOn)
{ {
return _latch = _drives[_driveNumber].Read(); if (!_writeMode)
{
return _latch = _drives[_driveNumber].Read();
}
else
{
WriteLatch();
}
} }
break; break;
@ -146,11 +153,9 @@ namespace Jellyfish.Virtu
case 0xC: case 0xC:
_loadMode = false; _loadMode = false;
if (_writeMode)
// write protect is forced if phase 1 is on [F9.7]
if ((_phaseStates & Phase1On) != 0)
{ {
_drives[_driveNumber].Write(_latch); WriteLatch();
} }
break; break;
@ -177,6 +182,15 @@ namespace Jellyfish.Virtu
} }
} }
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() private void Flush()
{ {
_drives[_driveNumber].FlushTrack(); _drives[_driveNumber].FlushTrack();

View File

@ -16,8 +16,7 @@ namespace Jellyfish.Virtu
public override void WriteTrack(int number, int fraction, byte[] buffer) public override void WriteTrack(int number, int fraction, byte[] buffer)
{ {
// TODO Buffer.BlockCopy(buffer, 0, Data, (number / 2) * TrackSize, TrackSize);
throw new NotImplementedException();
} }
} }
} }

View File

@ -13,15 +13,6 @@ 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 DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3
} }
public void FlushTrack()
{
if (_trackChanged)
{
// TODO
_trackChanged = false;
}
}
public void InsertDisk(string fileName, bool isWriteProtected) public void InsertDisk(string fileName, bool isWriteProtected)
{ {
FlushTrack(); FlushTrack();
@ -42,6 +33,7 @@ namespace Jellyfish.Virtu
int newTrackNumber = MathHelpers.Clamp(_trackNumber + delta, 0, TrackNumberMax); int newTrackNumber = MathHelpers.Clamp(_trackNumber + delta, 0, TrackNumberMax);
if (newTrackNumber != _trackNumber) if (newTrackNumber != _trackNumber)
{ {
FlushTrack();
_trackNumber = newTrackNumber; _trackNumber = newTrackNumber;
_trackOffset = 0; _trackOffset = 0;
_trackLoaded = false; _trackLoaded = false;
@ -69,6 +61,7 @@ namespace Jellyfish.Virtu
{ {
if (LoadTrack()) if (LoadTrack())
{ {
_trackChanged = true;
_trackData[_trackOffset++] = (byte)data; _trackData[_trackOffset++] = (byte)data;
if (_trackOffset >= Disk525.TrackSize) if (_trackOffset >= Disk525.TrackSize)
{ {
@ -88,6 +81,15 @@ namespace Jellyfish.Virtu
return _trackLoaded; return _trackLoaded;
} }
public void FlushTrack()
{
if (_trackChanged)
{
_disk.WriteTrack(_trackNumber, 0, _trackData);
_trackChanged = false;
}
}
public bool IsWriteProtected { get { return _disk.IsWriteProtected; } } public bool IsWriteProtected { get { return _disk.IsWriteProtected; } }
private const int TrackNumberMax = 0x44; private const int TrackNumberMax = 0x44;