openMSX
IDEHD.cc
Go to the documentation of this file.
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 
12 namespace openmsx {
13 
14 IDEHD::IDEHD(const DeviceConfig& config)
15  : HD(config)
16  , AbstractIDEDevice(config.getMotherBoard())
17  , diskManipulator(config.getReactor().getDiskManipulator())
18 {
19  transferSectorNumber = 0; // avoid UMR is serialize()
20  diskManipulator.registerDrive(
21  *this, strCat(config.getMotherBoard().getMachineID(), "::"));
22 }
23 
25 {
26  diskManipulator.unregisterDrive(*this);
27 }
28 
29 bool IDEHD::isPacketDevice()
30 {
31  return false;
32 }
33 
34 const std::string& IDEHD::getDeviceName()
35 {
36  static const std::string NAME = "OPENMSX HARD DISK";
37  return NAME;
38 }
39 
40 void IDEHD::fillIdentifyBlock(AlignedBuffer& buf)
41 {
42  auto totalSectors = getNbSectors();
43  uint16_t heads = 16;
44  uint16_t sectors = 32;
45  auto cylinders = uint16_t(totalSectors / (heads * sectors)); // TODO overflow?
46  Endian::writeL16(&buf[1 * 2], cylinders);
47  Endian::writeL16(&buf[3 * 2], heads);
48  Endian::writeL16(&buf[6 * 2], sectors);
49 
50  buf[47 * 2 + 0] = 16; // max sector transfer per interrupt
51  buf[47 * 2 + 1] = 0x80; // specced value
52 
53  // .... 1...: IORDY supported (hardware signal used by PIO modes >3)
54  // .... ..1.: LBA supported
55  buf[49 * 2 + 1] = 0x0A;
56 
57  // TODO check for overflow
58  Endian::writeL32(&buf[60 * 2], unsigned(totalSectors));
59 }
60 
61 unsigned IDEHD::readBlockStart(AlignedBuffer& buf, unsigned count)
62 {
63  try {
64  assert(count >= 512);
65  (void)count; // avoid warning
66  readSector(transferSectorNumber,
67  *aligned_cast<SectorBuffer*>(buf));
68  ++transferSectorNumber;
69  return 512;
70  } catch (MSXException&) {
72  return 0;
73  }
74 }
75 
76 void IDEHD::writeBlockComplete(AlignedBuffer& buf, unsigned count)
77 {
78  try {
79  assert((count % 512) == 0);
80  unsigned num = count / 512;
81  for (unsigned i = 0; i < num; ++i) {
82  writeSector(transferSectorNumber++,
83  *aligned_cast<SectorBuffer*>(buf + 512 * i));
84  }
85  } catch (MSXException&) {
87  }
88 }
89 
90 void IDEHD::executeCommand(byte cmd)
91 {
92  if (0x10 <= cmd && cmd < 0x20) {
93  // Recalibrate
94  setError(0);
95  setByteCount(0);
96  return;
97  }
98  switch (cmd) {
99  case 0x20: // Read Sector
100  case 0x21: // Read Sector without Retry
101  case 0x30: // Write Sector
102  case 0x31: { // Write Sector without Retry
103  unsigned sectorNumber = getSectorNumber();
104  unsigned numSectors = getNumSectors();
105  if ((sectorNumber + numSectors) > getNbSectors()) {
106  // Note: The original code set ABORT as well, but that is not
107  // allowed according to the spec.
108  setError(IDNF);
109  break;
110  }
111  transferSectorNumber = sectorNumber;
112  if (cmd < 0x30) {
113  startLongReadTransfer(numSectors * 512);
114  } else {
115  startWriteTransfer(numSectors * 512);
116  }
117  break;
118  }
119 
120  case 0xF8: // Read Native Max Address
121  // We don't support the Host Protected Area feature set, but SymbOS
122  // uses only this particular command, so we support just this one.
123  // TODO this only supports 28-bit sector numbers
124  setSectorNumber(unsigned(getNbSectors()));
125  break;
126 
127  default: // all others
129  }
130 }
131 
132 
133 template<typename Archive>
134 void IDEHD::serialize(Archive& ar, unsigned /*version*/)
135 {
136  // don't serialize SectorAccessibleDisk, DiskContainer base classes
137  ar.template serializeBase<HD>(*this);
138  ar.template serializeBase<AbstractIDEDevice>(*this);
139  ar.serialize("transferSectorNumber", transferSectorNumber);
140 }
143 
144 } // namespace openmsx
openmsx::AbstractIDEDevice::startWriteTransfer
void startWriteTransfer(unsigned count)
Indicates the start of a write data transfer.
Definition: AbstractIDEDevice.cc:374
DiskManipulator.hh
Endian::writeL16
void writeL16(void *p, uint16_t x)
Definition: endian.hh:129
openmsx::DiskManipulator::registerDrive
void registerDrive(DiskContainer &drive, const std::string &prefix)
Definition: DiskManipulator.cc:52
serialize.hh
IDEHD.hh
openmsx::AbstractIDEDevice::IDNF
static constexpr byte IDNF
Definition: AbstractIDEDevice.hh:36
openmsx::IDEHD::~IDEHD
~IDEHD() override
Definition: IDEHD.cc:24
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
openmsx::DeviceConfig::getMotherBoard
MSXMotherBoard & getMotherBoard() const
Definition: DeviceConfig.cc:13
openmsx::IDEHD::serialize
void serialize(Archive &ar, unsigned version)
Definition: IDEHD.cc:134
openmsx::SectorAccessibleDisk::writeSector
void writeSector(size_t sector, const SectorBuffer &buf)
Definition: SectorAccessibleDisk.cc:36
openmsx::AbstractIDEDevice::setError
void setError(byte error)
Indicates an error: sets error register, error flag, aborts transfers.
Definition: AbstractIDEDevice.cc:231
LZ4::count
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
Definition: lz4.cc:207
openmsx::SectorAccessibleDisk::readSector
void readSector(size_t sector, SectorBuffer &buf)
Definition: SectorAccessibleDisk.cc:18
openmsx::SectorAccessibleDisk::getNbSectors
size_t getNbSectors() const
Definition: SectorAccessibleDisk.cc:52
openmsx::HD
Definition: HD.hh:22
MSXException.hh
Endian::writeL32
void writeL32(void *p, uint32_t x)
Definition: endian.hh:137
Reactor.hh
openmsx::AbstractIDEDevice::executeCommand
virtual void executeCommand(byte cmd)
Starts execution of an IDE command.
Definition: AbstractIDEDevice.cc:283
openmsx::MSXMotherBoard::getMachineID
std::string_view getMachineID() const
Definition: MSXMotherBoard.hh:69
openmsx::AbstractIDEDevice::setByteCount
void setByteCount(unsigned count)
Writes the byte count of a packet transfer in the registers.
Definition: AbstractIDEDevice.cc:265
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:982
endian.hh
openmsx::AbstractIDEDevice::UNC
static constexpr byte UNC
Definition: AbstractIDEDevice.hh:35
openmsx::AbstractIDEDevice::startLongReadTransfer
void startLongReadTransfer(unsigned count)
Indicates the start of a read data transfer which uses blocks.
Definition: AbstractIDEDevice.cc:354
openmsx::AbstractIDEDevice::getNumSectors
unsigned getNumSectors() const
Gets the number of sectors indicated by the sector count register.
Definition: AbstractIDEDevice.cc:250
openmsx::AbstractIDEDevice::getSectorNumber
unsigned getSectorNumber() const
Creates an LBA sector address from the contents of the sectorNumReg, cylinderLowReg,...
Definition: AbstractIDEDevice.cc:244
openmsx::AbstractIDEDevice::abortWriteTransfer
void abortWriteTransfer(byte error)
Aborts the write transfer in progress.
Definition: AbstractIDEDevice.cc:382
strCat.hh
openmsx::AbstractIDEDevice
Definition: AbstractIDEDevice.hh:14
openmsx::DiskManipulator::unregisterDrive
void unregisterDrive(DiskContainer &drive)
Definition: DiskManipulator.cc:66
DeviceConfig.hh
strCat
std::string strCat(Ts &&...ts)
Definition: strCat.hh:573
openmsx::AbstractIDEDevice::abortReadTransfer
void abortReadTransfer(byte error)
Aborts the read transfer in progress.
Definition: AbstractIDEDevice.cc:368
openmsx::IDEDevice
Definition: IDEDevice.hh:10
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::REGISTER_POLYMORPHIC_INITIALIZER
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
MSXMotherBoard.hh
openmsx::AbstractIDEDevice::setSectorNumber
void setSectorNumber(unsigned lba)
Writes a 28-bit LBA sector number in the registers.
Definition: AbstractIDEDevice.cc:271
openmsx::IDEHD
Definition: IDEHD.hh:13
openmsx::IDEHD::IDEHD
IDEHD(const IDEHD &)=delete