private void SeekAddressData(byte ByteRead, OpStatus NextStatus, bool Check) { damBytesChecked++; switch (opStatus) { case OpStatus.SeekingIDAM: if (IndexesFound >= 5) { SeekError = true; opStatus = OpStatus.NMI; } else { switch (ByteRead) { case Floppy.IDAM: if (track?.HasIdamAt(TrackDataIndex, DoubleDensitySelected) ?? false) { readAddressIndex = 0; ResetCRC(); crc = Lib.Crc(crc, ByteRead); opStatus = OpStatus.ReadingAddressData; } idamBytesFound = 0; break; default: idamBytesFound = 0; break; } } break; case OpStatus.ReadingAddressData: readAddressData[readAddressIndex] = ByteRead; if (readAddressIndex == ADDRESS_DATA_CRC_HIGH_BYTE - 1) { // save the value before the first crc on the sector comes in crcCalc = crc; } else if (readAddressIndex >= ADDRESS_DATA_CRC_LOW_BYTE) { damBytesChecked = 0; crcHigh = readAddressData[ADDRESS_DATA_CRC_HIGH_BYTE]; crcLow = readAddressData[ADDRESS_DATA_CRC_LOW_BYTE]; CrcError = crcCalc != Lib.CombineBytes(crcLow, crcHigh); var match = (TrackRegister == readAddressData[ADDRESS_DATA_TRACK_REGISTER_BYTE] && (!command.SideSelectVerify || (command.SideOneExpected == (readAddressData[ADDRESS_DATA_SIDE_ONE_BYTE] != 0))) && (SectorRegister == readAddressData[ADDRESS_DATA_SECTOR_REGISTER_BYTE])); if (Check && !match) { opStatus = OpStatus.SeekingIDAM; } else { sectorLength = Floppy.GetDataLengthFromCode(readAddressData[ADDRESS_DATA_SECTOR_SIZE_BYTE]); if (CrcError) { opStatus = OpStatus.SeekingIDAM; } else { opStatus = NextStatus; } } } readAddressIndex++; break; default: throw new Exception(); } }
internal static byte[] ToTrackBytes(IEnumerable <SectorDescriptor> Sectors, int Length = 0) { byte[] ret = new byte[MAX_LENGTH_WITH_HEADER * 2]; // big int i = 0; ret.SetValues(ref i, HEADER_LENGTH_BYTES, (byte)0x00); bool ddAll = Sectors.All(s => s.DoubleDensity); int headerCursor = 0; // In some places we use fewer bytes than the 1773 tech reference states so that we can fit // 18 DD sectors (or 10 SD sectors) in a standard length track. Not sure why WD made it // so the standard doesn't work. if (ddAll) { ret.SetValues(ref i, 10, (byte)0x4E) /* standard is 80 */ .SetValues(ref i, 12, (byte)0x00) .SetValues(ref i, 3, (byte)0xF6) .SetValues(ref i, 1, (byte)0xFC) .SetValues(ref i, 50, (byte)0x4E); /* standard is 50 */ } else { // times two for doubled bytes ret.SetValues(ref i, 10 * 2, (byte)0xFF) /* tech datasheet says 30, not 10 */ .SetValues(ref i, 6 * 2, (byte)0x00) .SetValues(ref i, 1 * 2, (byte)0xFC) .SetValues(ref i, 26 * 2, (byte)0xFF); } byte sideNum; byte dataLengthCode; byte b; foreach (var s in Sectors) { sideNum = s.Side; dataLengthCode = Floppy.GetDataLengthCode(s.SectorData.Length); ushort crc; if (s.DoubleDensity) { crc = Floppy.CRC_RESET_A1_A1_A1_FE; ret.SetValues(ref i, 12, (byte)0x00) .SetValues(ref i, 3, (byte)0xA1); ((ushort)(i + DOUBLE_DENSITY_MASK)).Split(out ret[headerCursor], out ret[headerCursor + 1]); } else { crc = Floppy.CRC_RESET_FE; ret.SetValues(ref i, 6 * 2, (byte)0x00); ((ushort)i).Split(out ret[headerCursor], out ret[headerCursor + 1]); } headerCursor += 2; ret.SetValues(ref i, !s.DoubleDensity, Floppy.IDAM, s.TrackNumber, sideNum, s.SectorNumber, dataLengthCode); crc = Lib.Crc(crc, s.TrackNumber, sideNum, s.SectorNumber, dataLengthCode); crc.Split(out byte crcLow, out byte crcHigh); if (s.DoubleDensity) { ret.SetValues(ref i, false, crcHigh, crcLow) .SetValues(ref i, 22, (byte)0x4E) .SetValues(ref i, 12, (byte)0x00) .SetValues(ref i, false, (byte)0xA1, (byte)0xA1, (byte)0xA1, s.DAM); crc = Lib.Crc(Floppy.CRC_RESET_A1_A1_A1, s.DAM); for (int j = 0; j < s.SectorData.Length; j++) { b = s.SectorData[j]; ret[i++] = b; crc = Lib.Crc(crc, b); } if (s.CrcError) { crc = (ushort)~crc; // trash the crc } crc.Split(out crcLow, out crcHigh); ret.SetValues(ref i, false, crcHigh, crcLow) .SetValues(ref i, 20, (byte)0x4E); /* standard is 54 */ } else // single density { ret.SetValues(ref i, true, crcHigh, crcLow) .SetValues(ref i, 11 * 2, (byte)0xFF) .SetValues(ref i, 6 * 2, (byte)0x00) .SetValues(ref i, 1 * 2, s.DAM); crc = Floppy.CRC_RESET; crc = Lib.Crc(crc, s.DAM); for (int j = 0; j < s.SectorData.Length; j++) { b = s.SectorData[j]; ret[i++] = b; ret[i++] = b; crc = Lib.Crc(crc, b); } if (s.CrcError) { crc = (ushort)~crc; // trash the crc } crc.Split(out crcLow, out crcHigh); ret.SetValues(ref i, 1 * 2, crcHigh) .SetValues(ref i, 1 * 2, crcLow) .SetValues(ref i, 17 * 2, (byte)0xFF); /* spec says 27, not 17 */ } } if (Length > 0) { ret = ret.Pad(Length, ddAll ? Floppy.FILLER_BYTE_DD : Floppy.FILLER_BYTE_SD).Slice(0, Length); } else if (i <= 0x0CC0) { ret = ret.Pad(0x0CC0, Floppy.FILLER_BYTE_SD); } else { ret = ret.Pad(DEFAULT_LENGTH_WITH_HEADER, ddAll ? Floppy.FILLER_BYTE_DD : Floppy.FILLER_BYTE_SD).Slice(0, MAX_LENGTH_WITH_HEADER); } return(ret); }
private List <SectorDescriptor> GetSectorDescriptorCache() { var sds = new List <SectorDescriptor>(); for (int SectorIndex = 0; SectorIndex < HEADER_LENGTH && Header[SectorIndex] > 0; SectorIndex++) { bool density = Header[SectorIndex] >= DOUBLE_DENSITY_MASK; int byteMultiple = density ? 1 : 2; int offset = (Header[SectorIndex] & OFFSET_MASK) - HEADER_LENGTH_BYTES; if (data[offset] != Floppy.IDAM) { continue; } byte trackNum = data[offset + 1 * byteMultiple]; bool sideOne = data[offset + 2 * byteMultiple] > 0; byte sectorNum = data[offset + 3 * byteMultiple]; byte dam = 0x00; int dataStart = 0x00; bool deleted = false; for (int i = offset + 7 * byteMultiple; i < offset + (7 + (density ? 43 : 30)) * byteMultiple; i += byteMultiple) { if (FloppyController.IsDAM(data[i], out deleted)) { dam = data[i]; dataStart = i + byteMultiple; break; } } var sizeCode = data[offset + 4 * byteMultiple]; var dataLength = Floppy.GetDataLengthFromCode(sizeCode); var sectorData = new byte[dataLength]; bool crcError; bool inUse; if (dam == 0x00) { crcError = true; inUse = false; } else { inUse = !deleted; ushort actualCrc = Lib.Crc(density ? Floppy.CRC_RESET_A1_A1_A1 : Floppy.CRC_RESET, dam); for (int i = 0; i < dataLength; i++) { sectorData[i] = data[dataStart + i * byteMultiple]; actualCrc = Lib.Crc(actualCrc, sectorData[i]); } ushort recordedCrc = Lib.CombineBytes(data[dataStart + (dataLength + 1) * byteMultiple], data[dataStart + dataLength * byteMultiple]); crcError = actualCrc != recordedCrc; } sds.Add(new SectorDescriptor(trackNum, sectorNum, sideOne, density, dam, sectorData, inUse, crcError)); } return(sds.OrderBy(s => s.SectorNumber).ToList()); }
private ushort[] RebuildHeader() { var header = new ushort[HEADER_LENGTH]; int headerCursor = 0; int end = data.Length - 10; int i = 4; while (i < end) { bool density = GetDensity(i); if (data[i] == Floppy.IDAM) { // is it a real IDAM? Check preceding bytes if (density) { if (data[i - 1] != 0xA1 || data[i - 2] != 0xA1 || data[i - 3] != 0xA1) { i++; continue; } } else { if (data[i - 2] != 0x00) { i += 2; continue; } } // commit without checking address crc, since could be intentional error header[headerCursor++] = (ushort)(i + HEADER_LENGTH_BYTES + (density ? DOUBLE_DENSITY_MASK : 0)); // now skip forward past the sector contents // advance to length if (density) { i += 4; } else { i += 8; } i += Floppy.GetDataLengthFromCode(data[i]) * (density ? 1 : 2); i += 20 * (density ? 1 : 2); // filler minimum } else { if (density) { i++; } else { i += 2; } } } this.header = header; return(this.header); }