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 @@ protected Disk525(string name, byte[] data, bool isWriteProtected)
{
Name = name;
Data = data;
IsWriteProtected = true; // TODO use isWriteProtected
IsWriteProtected = isWriteProtected;
}
public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected)

View File

@ -49,8 +49,124 @@ public override void ReadTrack(int number, int fraction, byte[] buffer)
public override void WriteTrack(int number, int fraction, byte[] buffer)
{
// TODO
throw new NotImplementedException();
if (IsWriteProtected)
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)
@ -134,5 +250,29 @@ private void WriteDataNibbles(int sectorOffset)
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
};
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,10 +75,17 @@ public int Read(int address)
case 0xC:
_loadMode = false;
if (_motorOn && !_writeMode)
if (_motorOn)
{
if (!_writeMode)
{
return _latch = _drives[_driveNumber].Read();
}
else
{
WriteLatch();
}
}
break;
case 0xD:
@ -146,11 +153,9 @@ public void Write(int address, int data)
case 0xC:
_loadMode = false;
// write protect is forced if phase 1 is on [F9.7]
if ((_phaseStates & Phase1On) != 0)
if (_writeMode)
{
_drives[_driveNumber].Write(_latch);
WriteLatch();
}
break;
@ -177,6 +182,15 @@ public void Write(int address, int 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();

View File

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

View File

@ -13,15 +13,6 @@ public Drive525()
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)
{
FlushTrack();
@ -42,6 +33,7 @@ public void ApplyPhaseChange(int phaseState)
int newTrackNumber = MathHelpers.Clamp(_trackNumber + delta, 0, TrackNumberMax);
if (newTrackNumber != _trackNumber)
{
FlushTrack();
_trackNumber = newTrackNumber;
_trackOffset = 0;
_trackLoaded = false;
@ -69,6 +61,7 @@ public void Write(int data)
{
if (LoadTrack())
{
_trackChanged = true;
_trackData[_trackOffset++] = (byte)data;
if (_trackOffset >= Disk525.TrackSize)
{
@ -88,6 +81,15 @@ private bool LoadTrack()
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;