/// <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);
        }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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);
        }
Example #5
0
        /// <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);
        }
Example #6
0
		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;
		}
Example #7
0
		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;
		}
Example #8
0
        /// <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);
        }