17 bool signalsNeedMotorOn_,
bool doubleSided,
19 : syncLoadingTimeout(motherBoard_.getScheduler())
20 , syncMotorTimeout (motherBoard_.getScheduler())
21 , motherBoard(motherBoard_)
23 motherBoard.getReactor().getGlobalSettings().getThrottleManager())
24 , motorTimeout(motorTimeout_)
25 , motorTimer(getCurrentTime())
26 , headPos(0), side(0), startAngle(0)
28 , doubleSizedDrive(doubleSided)
29 , signalsNeedMotorOn(signalsNeedMotorOn_)
30 , trackMode(trackMode_)
31 , trackValid(false), trackDirty(false)
33 drivesInUse = motherBoard.
getSharedStuff<DrivesInUse>(
"drivesInUse");
36 while ((*drivesInUse)[i]) {
37 if (++i == MAX_DRIVES) {
41 (*drivesInUse)[i] =
true;
42 std::string driveName =
"diskX"; driveName[4] = char(
'a' + i);
45 throw MSXException(
"Duplicated drive name: ", driveName);
48 changer.emplace(motherBoard, driveName,
true, doubleSizedDrive,
49 [
this]() { invalidateTrack(); });
59 doSetMotor(
false, getCurrentTime());
61 const auto& driveName = changer->getDriveName();
64 unsigned driveNum = driveName[4] -
'a';
65 assert((*drivesInUse)[driveNum]);
66 (*drivesInUse)[driveNum] =
false;
83 if (!doubleSizedDrive && (side != 0))
return false;
85 return !changer->getDisk().isDummyDisk();
92 if (signalsNeedMotorOn && !motorStatus)
return false;
93 return changer->getDisk().isWriteProtected();
98 return doubleSizedDrive ? changer->getDisk().isDoubleSided()
105 side = side_ ? 1 : 0;
113 unsigned RealDrive::getMaxTrack()
const
115 constexpr
unsigned MAX_TRACK = 85;
121 return MAX_TRACK * 4 + 3;
128 std::optional<unsigned> RealDrive::getDiskReadTrack()
const
141 if ((headPos >= 2) && ((headPos % 4) != 2)) {
142 return (headPos - 2) / 4;
152 std::optional<unsigned> RealDrive::getDiskWriteTrack()
const
159 if ((headPos >= 4) && ((headPos % 4) == 0)) {
160 return (headPos - 4) / 4;
176 if (headPos < getMaxTrack()) {
188 if (motorStatus) setLoading(time);
197 if (signalsNeedMotorOn && !motorStatus)
return false;
219 if (syncMotorTimeout.removeSyncPoint()) {
232 doSetMotor(
true, time);
239 if (syncMotorTimeout.pendingSyncPoint()) {
248 syncLoadingTimeout.removeSyncPoint();
249 loadingIndicator.
update(
false);
252 syncMotorTimeout.setSyncPoint(time + motorTimeout);
264 unsigned RealDrive::getCurrentAngle(EmuTime::param time)
const
269 return (startAngle + deltaAngle) % TICKS_PER_ROTATION;
276 void RealDrive::doSetMotor(
bool status, EmuTime::param time)
282 startAngle = getCurrentAngle(time);
283 motorStatus = status;
292 void RealDrive::setLoading(EmuTime::param time)
295 loadingIndicator.
update(
true);
300 syncLoadingTimeout.removeSyncPoint();
304 void RealDrive::execLoadingTimeout()
306 loadingIndicator.
update(
false);
309 void RealDrive::execMotorTimeout(EmuTime::param time)
311 doSetMotor(
false, time);
322 return getCurrentAngle(time) < INDEX_DURATION;
328 return EmuTime::infinity();
330 unsigned delta = TICKS_PER_ROTATION - getCurrentAngle(time);
333 return time + dur1 + dur2;
336 void RealDrive::invalidateTrack()
340 }
catch (MSXException&) {
346 void RealDrive::getTrack()
354 if (
auto rdTrack = getDiskReadTrack()) {
355 changer->getDisk().readTrack(*rdTrack, side, track);
375 track.
write(idx, val, addIdam);
382 return trackValid ? track.
read(idx) : 0;
385 static constexpr
unsigned divUp(
unsigned a,
unsigned b)
387 return (a + b - 1) / b;
392 int currentAngle = getCurrentAngle(time);
394 unsigned idx = divUp(currentAngle * trackLen, TICKS_PER_ROTATION);
406 return EmuTime::infinity();
408 int sectorAngle = divUp(sector.
addrIdx * TICKS_PER_ROTATION, trackLen);
412 int delta = sectorAngle - currentAngle;
413 if (delta < 4) delta += TICKS_PER_ROTATION;
414 assert(4 <= delta); assert(
unsigned(delta) < (TICKS_PER_ROTATION + 4));
421 if (trackValid && trackDirty) {
422 if (
auto wrTrack = getDiskWriteTrack()) {
423 changer->getDisk().writeTrack(*wrTrack, side, track);
431 return changer->diskChanged();
436 return changer->peekDiskChanged();
461 template<
typename Archive>
464 if (ar.versionAtLeast(version, 4)) {
465 ar.serialize(
"syncLoadingTimeout", syncLoadingTimeout,
466 "syncMotorTimeout", syncMotorTimeout);
470 ar.serialize(
"motorTimer", motorTimer,
474 "motorStatus", motorStatus);
475 if (ar.versionAtLeast(version, 3)) {
476 ar.serialize(
"startAngle", startAngle);
478 assert(Archive::IS_LOADER);
481 if (ar.versionAtLeast(version, 5)) {
482 ar.serialize(
"track", track);
483 ar.serialize(
"trackValid", trackValid);
484 ar.serialize(
"trackDirty", trackDirty);
486 if constexpr (Archive::IS_LOADER) {
virtual void update(UpdateType type, std::string_view name, std::string_view value)=0
constexpr uint64_t getTicksTillUp(EmuTime::param e) const
Calculate the number of ticks this clock has to tick to reach or go past the given time.
static constexpr EmuDuration duration(unsigned ticks)
Calculates the duration of the given number of ticks at this clock's frequency.
constexpr void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
static constexpr EmuDuration sec(unsigned x)
void setLed(Led led, bool status)
void update(bool newState)
Called by the device to indicate its loading state may have changed.
bool hasCommand(std::string_view command) const
CliComm & getMSXCliComm()
LedStatus & getLedStatus()
MSXCommandController & getMSXCommandController()
std::shared_ptr< T > getSharedStuff(std::string_view name, Args &&...args)
Some MSX device parts are shared between several MSX devices (e.g.
void write(int idx, byte val, bool setIdam=false)
std::optional< Sector > decodeNextSector(unsigned startIdx) const
Get the next sector (starting from a certain index).
void applyWd2793ReadTrackQuirk()
void clear(unsigned size)
Clear track data.
unsigned getLength() const
Get track length.
This class implements a real drive, single or double sided.
void applyWd2793ReadTrackQuirk() override
See RawTrack::applyWd2793ReadTrackQuirk()
bool peekDiskChanged() const override
void serialize(Archive &ar, unsigned version)
bool isTrack00() const override
Head above track 0.
void step(bool direction, EmuTime::param time) override
Step head.
bool isDoubleSided() override
Is disk double sided?
void invalidateWd2793ReadTrackQuirk() override
void writeTrackByte(int idx, byte val, bool addIdam) override
bool isWriteProtected() const override
Is disk write protected?
bool getMotor() const override
Returns the previously set motor status.
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
void setSide(bool side) override
Side select.
byte readTrackByte(int idx) override
bool diskChanged() override
Is disk changed?
bool indexPulse(EmuTime::param time) override
Gets the state of the index pulse.
RealDrive(MSXMotherBoard &motherBoard, EmuDuration::param motorTimeout, bool signalsNeedMotorOn, bool doubleSided, DiskDrive::TrackMode trackMode)
EmuTime getTimeTillIndexPulse(EmuTime::param time, int count) override
Return the time till the start of the next index pulse When there is no disk in the drive or when the...
bool isDummyDrive() const override
Is there a dummy (unconnected) drive?
void flushTrack() override
bool isDiskInserted() const override
Is drive ready?
EmuTime getNextSector(EmuTime::param time, RawTrack::Sector §or) override
unsigned getTrackLength() override
bool getSide() const override
static void restoreOld(Archive &ar, std::vector< Schedulable * > schedulables)
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
This file implemented 3 utility functions:
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)