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 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(); } }
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); }