/// <summary> /// Reads the LBA48. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool ReadLBA48(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive > MaximunDriveCount) { return(false); } FeaturePort.Write8(0); FeaturePort.Write8(0); SectorCountPort.Write8(0); SectorCountPort.Write8(1); LBALowPort.Write8((byte)((lba >> 24) & 0xFF)); LBALowPort.Write8((byte)(lba & 0xFF)); LBAMidPort.Write8((byte)((lba >> 32) & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 40) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); DeviceHeadPort.Write8((byte)(0x40 | (drive << 4))); if (operation == SectorOperation.Write) { CommandPort.Write8(0x34); } else { CommandPort.Write8(0x24); } if (!WaitForReqisterReady()) { return(false); } BinaryFormat sector = new BinaryFormat(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) { sector.SetUShort(offset + (index * 2), DataPort.Read16()); } } else { for (uint index = 0; index < 256; index++) { DataPort.Write16(sector.GetUShort(offset + (index * 2))); } } return(true); }
/// <summary> /// Reads the LBA48. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool PerformLBA48(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive >= MaximunDriveCount || !driveInfo[drive].Present) { return(false); } DeviceHeadPort.Write8((byte)(0x40 | (drive << 4))); SectorCountPort.Write8(0); LBALowPort.Write8((byte)((lba >> 24) & 0xFF)); //NOTE: There's no point in finding the upper 5-6 bytes in a 32bit number (which also fixes a bug: (lba >> 32) = lba -> addressing wrong blocks) //LBAMidPort.Write8((byte)((lba >> 32) & 0xFF)); LBAMidPort.Write8(0x0); //LBAHighPort.Write8((byte)((lba >> 40) & 0xFF)); LBAHighPort.Write8(0x0); SectorCountPort.Write8(1); LBALowPort.Write8((byte)(lba & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); CommandPort.Write8((byte)((operation == SectorOperation.Write) ? 0x34 : 0x24)); if (!WaitForReadyStatus()) { return(false); } var sector = new DataBlock(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) { sector.SetUShort(offset + (index * 2), DataPort.Read16()); } } else { for (uint index = 0; index < 128; index++) { DataPort.Write32(sector.GetUInt(offset + (index * 4))); } //Cache flush DoCacheFlush(); } return(true); }
/// <summary> /// Reads the LBA48. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool PerformLBA48(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive >= MaximumDriveCount || !driveInfo[drive].Present) { return(false); } DeviceHeadPort.Write8((byte)(0x40 | (drive << 4))); SectorCountPort.Write8(0); LBALowPort.Write8((byte)((lba >> 24) & 0xFF)); LBAMidPort.Write8((byte)((lba >> 32) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 40) & 0xFF)); SectorCountPort.Write8(1); LBALowPort.Write8((byte)(lba & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); FeaturePort.Write8(0); FeaturePort.Write8(0); CommandPort.Write8((byte)((operation == SectorOperation.Write) ? 0x34 : 0x24)); if (!WaitForReadyStatus()) { return(false); } var sector = new DataBlock(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) { sector.SetUShort(offset + (index * 2), DataPort.Read16()); } } else { for (uint index = 0; index < 128; index++) { DataPort.Write32(sector.GetUInt(offset + (index * 4))); } //Cache flush DoCacheFlush(); } return(true); }
/// <summary> /// Performs the LBA28. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive NBR.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool PerformLBA28(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive > MaximunDriveCount) { return(false); } FeaturePort.Write8(0); SectorCountPort.Write8(1); LBALowPort.Write8((byte)(lba & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); DeviceHeadPort.Write8((byte)(0xE0 | (drive << 4) | ((lba >> 24) & 0x0F))); if (operation == SectorOperation.Write) { CommandPort.Write8(IDECommands.WriteSectorsWithRetry); } else { CommandPort.Write8(IDECommands.ReadSectorsWithRetry); } if (!WaitForRegisterReady()) { return(false); } DataBlock sector = new DataBlock(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) { sector.SetUShort(offset + (index * 2), DataPort.Read16()); } } else { for (uint index = 0; index < 256; index++) { DataPort.Write16(sector.GetUShort(offset + (index * 2))); } } return(true); }
/// <summary> /// Performs the LBA28. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive NBR.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool PerformLBA28(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive >= MaximumDriveCount || !driveInfo[drive].Present) { return(false); } DeviceHeadPort.Write8((byte)(0xE0 | (drive << 4) | ((lba >> 24) & 0x0F))); FeaturePort.Write8(0); SectorCountPort.Write8(1); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBALowPort.Write8((byte)(lba & 0xFF)); CommandPort.Write8((operation == SectorOperation.Write) ? IDECommand.WriteSectorsWithRetry : IDECommand.ReadSectorsWithRetry); if (!WaitForReadyStatus()) { return(false); } var sector = new DataBlock(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) { sector.SetUShort(offset + (index * 2), DataPort.Read16()); } } else { //NOTE: Transferring 16bits at a time seems to fail(?) to write each second 16bits - transferring 32bits seems to fix this (???) for (uint index = 0; index < 128; index++) { DataPort.Write32(sector.GetUInt(offset + (index * 4))); } //Cache flush DoCacheFlush(); } return(true); }
protected bool PerformIO (SectorOperation operation, uint drive, byte sector, byte track, byte head, uint count, byte[] data, uint offset) { //TextMode.WriteLine("Sector: ", (int)sector); //TextMode.WriteLine("Track: ", (int)track); //TextMode.WriteLine("Head: ", (int)head); for (int i = 0; i < 5; i++) { int error = 0; TurnOnMotor (drive); //TODO: Check for disk change if (Seek (drive, track, head)) { if (operation == SectorOperation.Write) { floppyDMA.TransferIn (count * FDC.BytesPerSector, data, offset); floppyDMA.SetupChannel (DMAMode.ReadFromMemory, DMATransferType.Single, false, count * FDC.BytesPerSector); } else floppyDMA.SetupChannel (DMAMode.WriteToMemory, DMATransferType.Single, false, count * FDC.BytesPerSector); floppyIRQ.ClearInterrupt (); if (operation == SectorOperation.Write) SendByte (FIFOCommand.WriteSector | FIFOCommand.MFMModeMask); else SendByte (FIFOCommand.ReadSector | FIFOCommand.MFMModeMask); SendByte ((byte)((byte)drive | (head << 2))); // 0:0:0:0:0:HD:US1:US0 = head and drive SendByte (track);// C: SendByte (head); // H: first head (should match with above) SendByte ((byte)(sector + 1)); // R: first sector, strangely counts from 1 SendByte (2); // N: bytes/sector, 128*2^x (x=2 -> 512) SendByte ((byte)(sector + count)); // EOT SendByte (floppyMedia[drive].Gap1Length); // GPL: GAP3 length, 27 is default for 3.5" SendByte (0xFF); // DTL: (bytes to transfer) = unused if (!floppyIRQ.WaitForInterrupt (3000)) error = 3; byte st0 = GetByte (); byte st1 = GetByte (); byte st2 = GetByte (); byte trk = GetByte (); // track (cylinder) byte rhe = GetByte (); // head byte sec = GetByte (); // sector number byte bps = GetByte (); // bytes per sector //TextMode.WriteLine("ST0: ", (int)st0); //TextMode.WriteLine("ST1: ", (int)st1); //TextMode.WriteLine("ST2: ", (int)st2); //TextMode.WriteLine("TRK: ", (int)trk); //TextMode.WriteLine("RHE: ", (int)rhe); //TextMode.WriteLine("SEC: ", (int)sec); //TextMode.WriteLine("BPS: ", (int)bps); if ((st0 & 0xC0) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: error"); error = 1; } if (trk != track + 1) { if (verbose) TextMode.WriteLine ("FloppyDiskController: wrong track: ", trk - 1); error = 1; } if (rhe != head) { if (verbose) TextMode.WriteLine ("FloppyDiskController: wrong track: ", trk - 1); error = 1; } if ((st1 & 0x80) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: end of cylinder"); error = 1; } if ((st0 & 0x08) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: drive not ready"); error = 1; } if ((st1 & 0x20) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: CRC error"); error = 1; } if ((st1 & 0x10) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: controller timeout"); error = 1; } if ((st1 & 0x04) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: no data found"); error = 1; } if (((st1 | st2) & 0x01) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: no address mark found"); error = 1; } if ((st2 & 0x40) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: deleted address mark"); error = 1; } if ((st2 & 0x20) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: CRC error in data"); error = 1; } if ((st2 & 0x10) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: wrong cylinder"); error = 1; } if ((st2 & 0x04) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: sector not found"); error = 1; } if ((st2 & 0x02) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: bad cylinder"); error = 1; } if (bps != 0x02) { if (verbose) TextMode.WriteLine ("FloppyDiskController: wanted 512B/sector, got something else: ", (int)bps); error = 1; } if ((st1 & 0x02) != 0x0) { if (verbose) TextMode.WriteLine ("FloppyDiskController: not writable"); error = 2; } } else { error = 1; // seek failed } if (error == 0) { if (operation == SectorOperation.Write) return true; else if (floppyDMA.TransferOut (count * FDC.BytesPerSector, data, offset)) return true; return false; } lastSeek[drive].calibrated = false; // will force recalibration if (error > 1) { if (verbose) TextMode.WriteLine ("FloppyDiskController: not retrying.."); TurnOffMotor (drive); break; } } return false; }
protected bool PerformLBA28 (SectorOperation operation, uint driveNbr, uint lba, byte[] data, uint offset) { FeaturePort.Write8 (0); SectorCountPort.Write8 (1); LBALowPort.Write8 ((byte)(lba & 0xFF)); LBAMidPort.Write8 ((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8 ((byte)((lba >> 16) & 0xFF)); DeviceHeadPort.Write8 ((byte)(0xE0 | (driveNbr << 4) | ((lba >> 24) & 0x0F))); if (operation == SectorOperation.Write) CommandPort.Write8 (IDECommand.WriteSectorsWithRetry); else CommandPort.Write8 (IDECommand.ReadSectorsWithRetry); if (!WaitForReqisterReady ()) return false; BinaryFormat sector = new BinaryFormat (data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) sector.SetUShort (offset + (index * 2), DataPort.Read16 ()); } else { for (uint index = 0; index < 256; index++) DataPort.Write16 (sector.GetUShort (offset + (index * 2))); } return true; }
/// <summary> /// Reads the LBA48. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool ReadLBA48(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive > MaximunDriveCount) return false; FeaturePort.Write8(0); FeaturePort.Write8(0); SectorCountPort.Write8(0); SectorCountPort.Write8(1); LBALowPort.Write8((byte)((lba >> 24) & 0xFF)); LBALowPort.Write8((byte)(lba & 0xFF)); LBAMidPort.Write8((byte)((lba >> 32) & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 40) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); DeviceHeadPort.Write8((byte)(0x40 | (drive << 4))); if (operation == SectorOperation.Write) CommandPort.Write8(0x34); else CommandPort.Write8(0x24); if (!WaitForRegisterReady()) return false; var sector = new BinaryFormat(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) sector.SetUShort(offset + (index * 2), DataPort.Read16()); } else { for (uint index = 0; index < 256; index++) DataPort.Write16(sector.GetUShort(offset + (index * 2))); } return true; }
/// <summary> /// Performs the IO. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive.</param> /// <param name="sector">The sector.</param> /// <param name="track">The track.</param> /// <param name="head">The head.</param> /// <param name="count">The count.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool PerformIO(SectorOperation operation, uint drive, byte sector, byte track, byte head, uint count, byte[] data, uint offset) { for (int i = 0; i < 5; i++) { int error = 0; TurnOnMotor(drive); //TODO: Check for disk change if (Seek(drive, track, head)) { if (operation == SectorOperation.Write) { floppyDMA.TransferIn(count * FDC.BytesPerSector, data, offset); floppyDMA.SetupChannel(DMAMode.ReadFromMemory, DMATransferType.Single, false, count * FDC.BytesPerSector); } else { floppyDMA.SetupChannel(DMAMode.WriteToMemory, DMATransferType.Single, false, count * FDC.BytesPerSector); } ClearInterrupt(); if (operation == SectorOperation.Write) { SendByte(FIFOCommand.WriteSector | FIFOCommand.MFMModeMask); } else { SendByte(FIFOCommand.ReadSector | FIFOCommand.MFMModeMask); } SendByte((byte)((byte)drive | (head << 2))); // 0:0:0:0:0:HD:US1:US0 = head and drive SendByte(track); // C: SendByte(head); // H: first head (should match with above) SendByte((byte)(sector + 1)); // R: first sector, strangely counts from 1 SendByte(2); // N: bytes/sector, 128*2^x (x=2 -> 512) SendByte((byte)(sector + count)); // EOT SendByte(floppyMedia[drive].Gap1Length); // GPL: GAP3 length, 27 is default for 3.5" SendByte(0xFF); // DTL: (bytes to transfer) = unused if (!WaitForInterrupt(3000)) { error = 3; } byte st0 = GetByte(); byte st1 = GetByte(); byte st2 = GetByte(); byte trk = GetByte(); // track (cylinder) byte rhe = GetByte(); // head //byte sec = GetByte(); // sector number GetByte(); // sector number byte bps = GetByte(); // bytes per sector if ((st0 & 0xC0) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: error"); error = 1; } if (trk != track + 1) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: wrong track: ", trk - 1); error = 1; } if (rhe != head) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: wrong track: ", trk - 1); error = 1; } if ((st1 & 0x80) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: end of cylinder"); error = 1; } if ((st0 & 0x08) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: drive not ready"); error = 1; } if ((st1 & 0x20) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: CRC error"); error = 1; } if ((st1 & 0x10) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: controller timeout"); error = 1; } if ((st1 & 0x04) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: no data found"); error = 1; } if (((st1 | st2) & 0x01) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: no address mark found"); error = 1; } if ((st2 & 0x40) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: deleted address mark"); error = 1; } if ((st2 & 0x20) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: CRC error in data"); error = 1; } if ((st2 & 0x10) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: wrong cylinder"); error = 1; } if ((st2 & 0x04) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: sector not found"); error = 1; } if ((st2 & 0x02) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: bad cylinder"); error = 1; } if (bps != 0x02) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: wanted 512B/sector, got something else: ", (int)bps); error = 1; } if ((st1 & 0x02) != 0x0) { //if (verbose) TextMode.WriteLine ("FloppyDiskController: not writable"); error = 2; } } else { error = 1; // seek failed } if (error == 0) { if (operation == SectorOperation.Write) { return(true); } else if (floppyDMA.TransferOut(count * FDC.BytesPerSector, data, offset)) { return(true); } return(false); } lastSeek[drive].calibrated = false; // will force recalibration if (error > 1) { TurnOffMotor(drive); break; } } return(false); }