15 : motherBoard(motherBoard_)
20 , transferWrite(false)
22 memset(buffer, 0,
sizeof(buffer));
25 byte AbstractIDEDevice::diagnostic()
34 void AbstractIDEDevice::createSignature(
bool preserveDevice)
36 sectorCountReg = 0x01;
39 cylinderLowReg = 0x14;
40 cylinderHighReg = 0xEB;
50 cylinderLowReg = 0x00;
51 cylinderHighReg = 0x00;
58 errorReg = diagnostic();
62 setTransferRead(
false);
63 setTransferWrite(
false);
73 return sectorCountReg;
79 return cylinderLowReg;
82 return cylinderHighReg;
109 nibble reg,
byte value, EmuTime::param
118 sectorCountReg = value;
122 sectorNumReg = value;
126 cylinderLowReg = value;
130 cylinderHighReg = value;
139 statusReg &= ~(
DRQ |
ERR);
140 setTransferRead(
false);
141 setTransferWrite(
false);
168 assert((transferIdx + 1) <
sizeof(buffer));
169 word result = (buffer[transferIdx + 0] << 0) +
170 (buffer[transferIdx + 1] << 8);
173 if (bufferLeft == 0) {
174 if (transferCount == 0) {
176 setTransferRead(
false);
187 void AbstractIDEDevice::readNextBlock()
190 buffer, std::min<unsigned>(
sizeof(buffer), transferCount));
191 assert((bufferLeft & 1) == 0);
193 transferCount -= bufferLeft;
198 if (!transferWrite) {
202 assert((transferIdx + 1) <
sizeof(buffer));
203 buffer[transferIdx + 0] = value & 0xFF;
204 buffer[transferIdx + 1] = value >> 8;
207 if (bufferLeft == 0) {
208 unsigned bytesInBuffer = transferIdx;
209 if (transferCount == 0) {
211 setTransferWrite(
false);
223 void AbstractIDEDevice::writeNextBlock()
226 bufferLeft = std::min<unsigned>(
sizeof(buffer), transferCount);
227 transferCount -= bufferLeft;
239 setTransferWrite(
false);
240 setTransferRead(
false);
245 return sectorNumReg | (cylinderLowReg << 8) |
246 (cylinderHighReg << 16) | ((devHeadReg & 0x0F) << 24);
251 return (sectorCountReg == 0) ? 256 : sectorCountReg;
256 sectorCountReg = value;
261 return cylinderLowReg | (cylinderHighReg << 8);
266 cylinderLowReg =
count & 0xFF;
267 cylinderHighReg =
count >> 8;
272 sectorNumReg = (lba & 0x000000FF) >> 0;
273 cylinderLowReg = (lba & 0x0000FF00) >> 8;
274 cylinderHighReg = (lba & 0x00FF0000) >> 16;
275 devHeadReg = (lba & 0x0F000000) >> 24;
287 errorReg = diagnostic();
288 createSignature(
true);
299 errorReg = diagnostic();
328 fprintf(stderr,
"Unhandled set feature subcommand: %02X\n",
335 fprintf(stderr,
"unsupported IDE command %02X\n", cmd);
342 assert(
count <=
sizeof(buffer));
343 assert((
count & 1) == 0);
349 memset(buffer, 0x00,
count);
355 assert((
count & 1) == 0);
357 transferCount =
count;
361 void AbstractIDEDevice::startReadTransfer()
364 setTransferRead(
true);
370 setTransferRead(
false);
376 setTransferWrite(
true);
377 transferCount =
count;
384 setTransferWrite(
false);
387 void AbstractIDEDevice::setTransferRead(
bool status)
389 if (status != transferRead) {
390 transferRead = status;
391 if (!transferWrite) {
398 void AbstractIDEDevice::setTransferWrite(
bool status)
400 if (status != transferWrite) {
401 transferWrite = status;
417 static void writeIdentifyString(
byte* p,
unsigned len, std::string s)
419 s.resize(2 * len,
' ');
420 for (
auto i :
xrange(len)) {
422 p[2 * i + 0] = s[2 * i + 1];
423 p[2 * i + 1] = s[2 * i + 0];
427 void AbstractIDEDevice::createIdentifyBlock(AlignedBuffer& buf)
431 writeIdentifyString(&buf[10 * 2], 10,
"s00000001");
432 writeIdentifyString(&buf[23 * 2], 4,
437 writeIdentifyString(&buf[27 * 2], 20, std::string(
getDeviceName()));
443 template<
typename Archive>
447 ar.serialize_blob(
"buffer", buffer,
sizeof(buffer));
448 ar.serialize(
"transferIdx", transferIdx,
449 "bufferLeft", bufferLeft,
450 "transferCount", transferCount,
451 "errorReg", errorReg,
452 "sectorCountReg", sectorCountReg,
453 "sectorNumReg", sectorNumReg,
454 "cylinderLowReg", cylinderLowReg,
455 "cylinderHighReg", cylinderHighReg,
456 "devHeadReg", devHeadReg,
457 "statusReg", statusReg,
458 "featureReg", featureReg);
459 bool transferIdentifyBlock =
false;
461 ar.serialize(
"transferIdentifyBlock", transferIdentifyBlock,
462 "transferRead", transferRead,
463 "transferWrite", transferWrite);
void writeData(word value, EmuTime::param time) override
void startWriteTransfer(unsigned count)
Indicates the start of a write data transfer.
byte getFeatureReg() const
AlignedBuffer & startShortReadTransfer(unsigned count)
Indicates the start of a read data transfer where all data fits into the buffer at once.
virtual bool isPacketDevice()=0
Is this device a packet (ATAPI) device?
static constexpr byte DRDY
void startLongReadTransfer(unsigned count)
Indicates the start of a read data transfer which uses blocks.
void serialize(Archive &ar, unsigned version)
virtual void executeCommand(byte cmd)
Starts execution of an IDE command.
void writeReg(nibble reg, byte value, EmuTime::param time) override
static constexpr byte DRQ
static constexpr byte ERR
virtual void fillIdentifyBlock(AlignedBuffer &buffer)=0
Tells a subclass to fill the device specific parts of the identify block located in the buffer.
void setSectorNumber(unsigned lba)
Writes a 28-bit LBA sector number in the registers.
void setByteCount(unsigned count)
Writes the byte count of a packet transfer in the registers.
virtual std::string_view getDeviceName()=0
Gets the device name to insert as "model number" into the identify block.
static constexpr byte DSC
virtual unsigned readBlockStart(AlignedBuffer &buffer, unsigned count)=0
Called when a block of read data should be buffered by the controller: when the buffer is empty or at...
unsigned getNumSectors() const
Gets the number of sectors indicated by the sector count register.
void abortReadTransfer(byte error)
Aborts the read transfer in progress.
unsigned getByteCount() const
Reads the byte count limit of a packet transfer in the registers.
void setError(byte error)
Indicates an error: sets error register, error flag, aborts transfers.
byte readReg(nibble reg, EmuTime::param time) override
void abortWriteTransfer(byte error)
Aborts the write transfer in progress.
AbstractIDEDevice(MSXMotherBoard &motherBoard)
void reset(EmuTime::param time) override
unsigned getSectorNumber() const
Creates an LBA sector address from the contents of the sectorNumReg, cylinderLowReg,...
void setInterruptReason(byte value)
Writes the interrupt reason register.
virtual void writeBlockComplete(AlignedBuffer &buffer, unsigned count)=0
Called when a block of written data has been buffered by the controller: when the buffer is full or a...
word readData(EmuTime::param time) override
virtual void readEnd()
Called when a read transfer completes.
static constexpr byte ABORT
void setLed(Led led, bool status)
LedStatus & getLedStatus()
static const char *const VERSION
static const bool RELEASE
static const char *const REVISION
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
This file implemented 3 utility functions:
uint8_t nibble
4 bit integer
uint16_t word
16 bit unsigned integer
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
std::string strCat(Ts &&...ts)
constexpr auto xrange(T e)