IDEHD.cc 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #include "IDEHD.hh"
  2. #include "MSXException.hh"
  3. #include "DeviceConfig.hh"
  4. #include "MSXMotherBoard.hh"
  5. #include "Reactor.hh"
  6. #include "DiskManipulator.hh"
  7. #include "endian.hh"
  8. #include "serialize.hh"
  9. #include "strCat.hh"
  10. #include <cassert>
  11. namespace openmsx {
  12. IDEHD::IDEHD(const DeviceConfig& config)
  13. : HD(config)
  14. , AbstractIDEDevice(config.getMotherBoard())
  15. , diskManipulator(config.getReactor().getDiskManipulator())
  16. {
  17. transferSectorNumber = 0; // avoid UMR is serialize()
  18. diskManipulator.registerDrive(
  19. *this, strCat(config.getMotherBoard().getMachineID(), "::"));
  20. }
  21. IDEHD::~IDEHD()
  22. {
  23. diskManipulator.unregisterDrive(*this);
  24. }
  25. bool IDEHD::isPacketDevice()
  26. {
  27. return false;
  28. }
  29. const std::string& IDEHD::getDeviceName()
  30. {
  31. static const std::string NAME = "OPENMSX HARD DISK";
  32. return NAME;
  33. }
  34. void IDEHD::fillIdentifyBlock(AlignedBuffer& buf)
  35. {
  36. auto totalSectors = getNbSectors();
  37. uint16_t heads = 16;
  38. uint16_t sectors = 32;
  39. auto cylinders = uint16_t(totalSectors / (heads * sectors)); // TODO overflow?
  40. Endian::writeL16(&buf[1 * 2], cylinders);
  41. Endian::writeL16(&buf[3 * 2], heads);
  42. Endian::writeL16(&buf[6 * 2], sectors);
  43. buf[47 * 2 + 0] = 16; // max sector transfer per interrupt
  44. buf[47 * 2 + 1] = 0x80; // specced value
  45. // .... 1...: IORDY supported (hardware signal used by PIO modes >3)
  46. // .... ..1.: LBA supported
  47. buf[49 * 2 + 1] = 0x0A;
  48. // TODO check for overflow
  49. Endian::writeL32(&buf[60 * 2], unsigned(totalSectors));
  50. }
  51. unsigned IDEHD::readBlockStart(AlignedBuffer& buf, unsigned count)
  52. {
  53. try {
  54. assert(count >= 512);
  55. (void)count; // avoid warning
  56. readSector(transferSectorNumber,
  57. *aligned_cast<SectorBuffer*>(buf));
  58. ++transferSectorNumber;
  59. return 512;
  60. } catch (MSXException&) {
  61. abortReadTransfer(UNC);
  62. return 0;
  63. }
  64. }
  65. void IDEHD::writeBlockComplete(AlignedBuffer& buf, unsigned count)
  66. {
  67. try {
  68. assert((count % 512) == 0);
  69. unsigned num = count / 512;
  70. for (unsigned i = 0; i < num; ++i) {
  71. writeSector(transferSectorNumber++,
  72. *aligned_cast<SectorBuffer*>(buf + 512 * i));
  73. }
  74. } catch (MSXException&) {
  75. abortWriteTransfer(UNC);
  76. }
  77. }
  78. void IDEHD::executeCommand(byte cmd)
  79. {
  80. if (0x10 <= cmd && cmd < 0x20) {
  81. // Recalibrate
  82. setError(0);
  83. setByteCount(0);
  84. return;
  85. }
  86. switch (cmd) {
  87. case 0x20: // Read Sector
  88. case 0x21: // Read Sector without Retry
  89. case 0x30: // Write Sector
  90. case 0x31: { // Write Sector without Retry
  91. unsigned sectorNumber = getSectorNumber();
  92. unsigned numSectors = getNumSectors();
  93. if ((sectorNumber + numSectors) > getNbSectors()) {
  94. // Note: The original code set ABORT as well, but that is not
  95. // allowed according to the spec.
  96. setError(IDNF);
  97. break;
  98. }
  99. transferSectorNumber = sectorNumber;
  100. if (cmd < 0x30) {
  101. startLongReadTransfer(numSectors * 512);
  102. } else {
  103. startWriteTransfer(numSectors * 512);
  104. }
  105. break;
  106. }
  107. case 0xF8: // Read Native Max Address
  108. // We don't support the Host Protected Area feature set, but SymbOS
  109. // uses only this particular command, so we support just this one.
  110. // TODO this only supports 28-bit sector numbers
  111. setSectorNumber(unsigned(getNbSectors()));
  112. break;
  113. default: // all others
  114. AbstractIDEDevice::executeCommand(cmd);
  115. }
  116. }
  117. template<typename Archive>
  118. void IDEHD::serialize(Archive& ar, unsigned /*version*/)
  119. {
  120. // don't serialize SectorAccessibleDisk, DiskContainer base classes
  121. ar.template serializeBase<HD>(*this);
  122. ar.template serializeBase<AbstractIDEDevice>(*this);
  123. ar.serialize("transferSectorNumber", transferSectorNumber);
  124. }
  125. INSTANTIATE_SERIALIZE_METHODS(IDEHD);
  126. REGISTER_POLYMORPHIC_INITIALIZER(IDEDevice, IDEHD, "IDEHD");
  127. } // namespace openmsx