123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- #ifndef ABSTRACTIDEDEVICE_HH
- #define ABSTRACTIDEDEVICE_HH
- #include "IDEDevice.hh"
- #include "AlignedBuffer.hh"
- #include "serialize_meta.hh"
- #include <string>
- namespace openmsx {
- class MSXMotherBoard;
- class AbstractIDEDevice : public IDEDevice
- {
- public:
- void reset(EmuTime::param time) override;
- word readData(EmuTime::param time) override;
- byte readReg(nibble reg, EmuTime::param time) override;
- void writeData(word value, EmuTime::param time) override;
- void writeReg(nibble reg, byte value, EmuTime::param time) override;
- template<typename Archive>
- void serialize(Archive& ar, unsigned version);
- protected:
- // Bit flags for the status register:
- static constexpr byte DRDY = 0x40;
- static constexpr byte DSC = 0x10;
- static constexpr byte DRQ = 0x08;
- static constexpr byte ERR = 0x01;
- // Bit flags for the error register:
- static constexpr byte UNC = 0x40;
- static constexpr byte IDNF = 0x10;
- static constexpr byte ABORT = 0x04;
- explicit AbstractIDEDevice(MSXMotherBoard& motherBoard);
- ~AbstractIDEDevice() override = default;
- /** Is this device a packet (ATAPI) device?
- * @return True iff this device supports the packet commands.
- */
- virtual bool isPacketDevice() = 0;
- /** Gets the device name to insert as "model number" into the identify
- * block.
- * @return An ASCII string, up to 40 characters long.
- */
- virtual const std::string& getDeviceName() = 0;
- /** Tells a subclass to fill the device specific parts of the identify
- * block located in the buffer.
- * The generic part is already written there.
- * @param buffer Array of 512 bytes.
- */
- virtual void fillIdentifyBlock(AlignedBuffer& buffer) = 0;
- /** Called when a block of read data should be buffered by the controller:
- * when the buffer is empty or at the start of the transfer.
- * @param buffer Pointer to the start of a byte array.
- * @param count Number of bytes to be filled by this method.
- * This number will not exceed the array size nor the transfer length.
- * @return The number of bytes that was added to the array,
- * or 0 if the transfer was aborted (the implementation of this method
- * must set the relevant error flags as well).
- */
- virtual unsigned readBlockStart(AlignedBuffer& buffer, unsigned count) = 0;
- /** Called when a read transfer completes.
- * The default implementation does nothing.
- */
- virtual void readEnd();
- /** Called when a block of written data has been buffered by the controller:
- * when the buffer is full or at the end of the transfer.
- * @param buffer Pointer to the start of a byte array.
- * @param count Number of data bytes in the array.
- */
- virtual void writeBlockComplete(AlignedBuffer& buffer, unsigned count) = 0;
- /** Starts execution of an IDE command.
- * Override this to implement additional commands and make sure you call
- * the superclass implementation for all commands that you don't handle.
- */
- virtual void executeCommand(byte cmd);
- /** Indicates an error: sets error register, error flag, aborts transfers.
- * @param error Value to be written to the error register.
- */
- void setError(byte error);
- /** Creates an LBA sector address from the contents of the sectorNumReg,
- * cylinderLowReg, cylinderHighReg and devHeadReg registers.
- */
- unsigned getSectorNumber() const;
- /** Gets the number of sectors indicated by the sector count register.
- */
- unsigned getNumSectors() const;
- /** Writes the interrupt reason register.
- * This is the same as register as sector count, but serves a different
- * purpose.
- */
- void setInterruptReason(byte value);
- /** Reads the byte count limit of a packet transfer in the registers.
- * The cylinder low/high registers are used for this.
- */
- unsigned getByteCount() const;
- /** Writes the byte count of a packet transfer in the registers.
- * The cylinder low/high registers are used for this.
- */
- void setByteCount(unsigned count);
- /** Writes a 28-bit LBA sector number in the registers.
- * The cylinder low/high registers are used for this.
- */
- void setSectorNumber(unsigned lba);
- /** Indicates the start of a read data transfer which uses blocks.
- * The readBlockStart() method is called at the start of each block.
- * The first block will be read immediately, so make sure you initialise
- * all variables needed by readBlockStart() before calling this method.
- * @param count Total number of bytes to transfer.
- */
- void startLongReadTransfer(unsigned count);
- /** Indicates the start of a read data transfer where all data fits
- * into the buffer at once.
- * @param count Total number of bytes to transfer.
- * @return Pointer to the start of the buffer.
- * The caller should write the data there.
- * The relevant part of the buffer contains zeroes.
- */
- AlignedBuffer& startShortReadTransfer(unsigned count);
- /** Aborts the read transfer in progress.
- */
- void abortReadTransfer(byte error);
- /** Indicates the start of a write data transfer.
- * @param count Total number of bytes to transfer.
- */
- void startWriteTransfer(unsigned count);
- /** Aborts the write transfer in progress.
- */
- void abortWriteTransfer(byte error);
- byte getFeatureReg() const { return featureReg; }
- void setLBALow (byte value) { sectorNumReg = value; }
- void setLBAMid (byte value) { cylinderLowReg = value; }
- void setLBAHigh(byte value) { cylinderHighReg = value; }
- MSXMotherBoard& getMotherBoard() const { return motherBoard; }
- private:
- /** Perform diagnostic and return result.
- * Actually, just return success, because we don't emulate faulty hardware.
- */
- byte diagnostic();
- /** Puts special values in the sector address, sector count and device
- * registers to identify the type of device.
- * @param preserveDevice If true, preserve the value of the DEV bit;
- * if false, set the DEV bit to 0.
- */
- void createSignature(bool preserveDevice = false);
- /** Puts the output for the IDENTIFY DEVICE command in the buffer.
- * @param buffer Pointer to the start of the buffer.
- * The buffer must be at least 512 bytes in size.
- */
- void createIdentifyBlock(AlignedBuffer& buffer);
- /** Initialises registers for a data transfer.
- */
- void startReadTransfer();
- /** Initialises buffer related variables for the next data block.
- * Calls readBlockStart() to deliver the actual data.
- */
- void readNextBlock();
- /** Indicates that a read transfer starts.
- */
- void setTransferRead(bool status);
- /** Initialises buffer related variables for the next data block.
- * Make sure transferCount is initialised before calling this method.
- */
- void writeNextBlock();
- /** Indicates that a write transfer starts.
- */
- void setTransferWrite(bool status);
- MSXMotherBoard& motherBoard;
- /** Data buffer shared by all transfers.
- * The size must be a multiple of 512.
- * Right now I don't see any reason to make it larger than the minimum
- * size of 1 * 512.
- */
- AlignedByteArray<512> buffer;
- /** Index of current read/write position in the buffer.
- */
- unsigned transferIdx;
- /** Number of bytes remaining in the buffer.
- */
- unsigned bufferLeft;
- /** Number of bytes remaining in the transfer after this buffer.
- * (total bytes remaining == transferCount + bufferLeft)
- */
- unsigned transferCount;
- // ATA registers:
- byte errorReg;
- byte sectorCountReg;
- byte sectorNumReg;
- byte cylinderLowReg;
- byte cylinderHighReg;
- byte devHeadReg;
- byte statusReg;
- byte featureReg;
- bool transferRead;
- bool transferWrite;
- };
- REGISTER_BASE_NAME_HELPER(AbstractIDEDevice, "IDEDevice");
- } // namespace openmsx
- #endif // ABSTRACTIDEDEVICE_HH
|