#ifndef FLOPPY_H #define FLOPPY_H #include "your definition of byte, etc." #include "stdbool.h" #include "your Port IO file" #include "your DMA file" //#include "your interrupt handler" // if you are going to set up InterruptRaised with it in your floppy implementation, not elsewhere void DetectDrives(); class Floppy { public: // Drive types enum DriveType { drvNone = 0, drv5_25_360KB = 1, drv5_25_1_2MB = 2, drv3_5_720KB = 3, drv3_5_1_44MB = 4, drv3_5_2_88MB = 5 }; typedef byte * DataBlock; static void Initialize(byte IndexOfDrive, DriveType TypeOfDrive); static DataBlock Read(unsigned int BlockIndex); static void InterruptRaised(byte Interrupt); private: enum Mode { modRead = 0, modWrite = 1 }; // Control Configuration Register (CCR) enum CCR { ccrDataRate500Kb = 0, ccrDataRate300Kb = 1, ccrDataRate250Kb = 2, ccrDataRate1Mb = 3 // 500Kb works with 1.44MB disks in a 3.5" drive; slower speeds are necessary for other combinations }; static bool ReadWrite(unsigned int BlockIndex, Mode ReadOrWrite); static void Start(); static void Stop(); static void Reset(); static void SetDataRate(CCR DataRate); static bool SetSpecifications(byte StepRate, byte HeadUnloadTime, byte HeadLoadTime); static bool Recalibrate(); static bool SeekCylinder(byte Head, byte Cylinder); static void StartMotor(); static void StopMotor(); static bool ReadSectorStatus(byte Head, byte Sector, byte SectorSize); static bool ReadStatus(); static bool SendData(byte Data); static bool GetData(byte & Data); // Digital Output Register (DOR) enum DOR { dorMotorShift = 4, dorNoReset = 4, dorDMA = 8 // Bits 7 - 4 are drives D - A; use dorMotorShift + DriveIndex }; // Main Status Register enum MSR { msrMainRequest = 128, msrWaitingForDataIO = 64, msrNonDMA = 32, msrDeviceBusy = 16, msrPositioningActive = 1, msrPositioningHeadsShift = 0 // Bits 3 - 0 are drives D - A; use msrPositioningHeadsShift + DriveIndex }; // Status Registers 0 - 3 enum SR0 { st0NormalTermination = 0, st0AbnormalTermination = 64, st0InvalidCommand = 128, st0DriveBecameNotReady = 192, // st0DriveBecameNotReady: abnormal termination by polling st0SeekEnd = 32, st0UnitCheck = 16, // st0UnitCheck: If the drive faults or a recalibrate command can't find track 0 after 79 pulses st0DriveNotReady = 8, st0ActiveHeadIs1 = 4, st0SelectedDriveShift = 0 // Bits 1 - 0 are drives D - A; use st0SelectedDriveShift + DriveIndex }; enum SR1 { st1EndOfCylinder = 128, st1DataError = 32, st1TimeoutOverrun = 16, // st1EndOfCylinder: Sector count exceeds number of sectors on a track // st1TimeoutOverrun: no signal from DMA or CPU within the length of time required st1NoData = 4, st1NotWritable = 2, st1NoAddressMark = 1 }; enum SR2 { st2DeletedAddressMark = 64, st2CRCError = 32, st2WrongCylinder = 16, st2SeekEqual = 8, st2SeekError = 4, // st2SeekEqual and st2SeekError: Not used unless controller is a muPD765 (??) st2BadCylinder = 2, st2NoDataAddressMarkDAM = 1 }; enum SR3 { st3ErrorSignal = 128, st3WriteProtected = 64, st3Ready = 32, st3AtTrack0 = 16, // st3ErrorSignal and st3Ready: Not used unless controller is a muPD765 (??) st3IsDoubleSidedDrive = 8, st3ActiveHeadIs1 = 4, st3SelectedDriveShift = 0 }; // Digital Input Register (DIR) enum DIR { dirDiskChange = 128 // Other fields exist, but most can be found in other registers }; // Status registers A and B enum SRA { sraInterruptPending = 128, sraOnlyOneDrive = 64, sraStepperPulseSubmitted = 32, sraAtTrack0 = 16, sraActiveHeadIs1 = 8, sraIndexMarkDetected = 4, sraWriteProtected = 2, sraHeadDirectionInwards = 1 // sraHeadDirectionInwards: 1 if inwards toward higher cylinder numbers, 0 if outwards toward lower cylinder numbers }; enum SRB { srbSelectedDriveIs0 = 32, srbWriteCapable = 16, srbReadCapable = 8, srbWriteEnabled = 4, // srbWriteEnabled: 1 if head is set for writing data, 0 if set for reading data srbMotorShift = 0 // Bits 1 - 0 are drives B - A; use srbMotorShift + DriveIndex }; enum Commands { cmdReadTrack = 2, cmdSpecify = 3, cmdWriteSector = 5, cmdReadSector = 6, cmdWriteDeletedSector = 9, cmdReadDeletedSector = 12, cmdFormatTrack = 13, cmdCheckDriveStatus = 4, cmdCalibrateDrive = 7, cmdCheckInterruptStatus = 8, cmdReadSectorID = 10, cmdSeek = 15, cmdDetermineControllerVersion = 16, cmdVerify = 22, cmdSeekRelative = 143 }; enum CommandFields { cmdMultitrack = 128, cmdDoubleDensityMode = 64, cmdSkipDeletedSectors = 32, cmdGAP3Length = 27, // Only for 3.5"; for 5.25", standard is 42 and minimum is 32 cmdDriveShift = 0, cmdHeadShift = 2 }; enum SpecifyCommandParameters { // The milliseconds listed for the Step Rate, Head Unload Time, and Head Load Time are only for the 500Kbps data rate. spcStepRate16ms = 0, spcHeadUnloadTime256ms = 0, spcHeadLoadTime256ms = 0, spcStepRate3ms = 10, spcHeadUnloadTime240ms = 15, spcHeadLoadTime16ms = 1, // There are other settings, of course, but for now we should just stick to what works. spcNonDMAMode = 1, spcStepRateShift = 4, spcHeadUnloadTimeShift = 0, spcHeadLoadTimeShift = 1 }; // Constants ----------------------------------------------------------------------- // Floppy IO ports static const unsigned short IOBase[2]; static const unsigned short flpRStatusRegisterA, rFloppyStatusRegisterB, flpWDigitalOutputRegister, flpRMainStatusRegister, flpWDataRateSelect, flpRWDataRegister, flpRDigitalInputRegister, flpWConfigurationControlRegister; static const unsigned int MaximumReadWriteTries, MaximumSeekTries, MaximumRecalibrateTries; static const unsigned int MaximumSendTries, MaximumGetTries; static const unsigned int WaitDelay, SeekDelay, MotorOnDelay; // Variables ----------------------------------------------------------------------- static byte ControllerIndex, DriveIndex; static DriveType Type; static byte AtCylinder; static bool MotorRunning, DiskChanged; // Floppy drive status registers static byte DigitalOutputRegister, StatusRegister0, StatusRegister1, StatusRegister2; static bool PendingInterrupt; }; // Constants ----------------------------------------------------------------------------------- // Floppy IO ports const unsigned short Floppy::IOBase[2] = {0x3F0, 0x370}; const unsigned short Floppy::flpRStatusRegisterA = 0, Floppy::rFloppyStatusRegisterB = 1, Floppy::flpWDigitalOutputRegister = 2, Floppy::flpRMainStatusRegister = 4, Floppy::flpWDataRateSelect = 4, Floppy::flpRWDataRegister = 5, Floppy::flpRDigitalInputRegister = 7, Floppy::flpWConfigurationControlRegister = 7; const unsigned int Floppy::MaximumReadWriteTries = 5, Floppy::MaximumSeekTries = 2, Floppy::MaximumRecalibrateTries = 5; const unsigned int Floppy::MaximumSendTries = 10000, Floppy::MaximumGetTries = 10000; const unsigned int Floppy::WaitDelay = 75, Floppy::SeekDelay = 15, Floppy::MotorOnDelay = 500; // Variables ----------------------------------------------------------------------------------- byte Floppy::ControllerIndex = 0, Floppy::DriveIndex = 0; // Default to the first drive of the first controller. Currently this is the only place to set the controller index; if you want to support both controllers, you will want to add code for setting the controller index. Floppy::DriveType Floppy::Type = drvNone; // Assume no drive until told otherwise. byte Floppy::AtCylinder = 255; bool Floppy::MotorRunning = false, Floppy::DiskChanged = false; // Floppy drive status registers byte Floppy::DigitalOutputRegister = dorNoReset | dorDMA, Floppy::StatusRegister0 = 0, Floppy::StatusRegister1 = 0, Floppy::StatusRegister2 = 0; bool Floppy::PendingInterrupt = false; // A 3.5" 1.44MB floppy disk has: Sectors (1 - 18), Heads (0 - 1), and Cylinders (0 - 79), for a total of 2880 sectors. #endif