21 bool signalsNeedMotorOn_,
bool doubleSided,
23 : syncLoadingTimeout(motherBoard_.getScheduler())
24 , syncMotorTimeout (motherBoard_.getScheduler())
25 , motherBoard(motherBoard_)
27 motherBoard.getReactor().getGlobalSettings().getThrottleManager())
28 , motorTimeout(motorTimeout_)
29 , motorTimer(getCurrentTime())
30 , doubleSizedDrive(doubleSided)
31 , signalsNeedMotorOn(signalsNeedMotorOn_)
32 , trackMode(trackMode_)
34 drivesInUse = motherBoard.
getSharedStuff<DrivesInUse>(
"drivesInUse");
37 while ((*drivesInUse)[i]) {
38 if (++i == MAX_DRIVES) {
42 (*drivesInUse)[i] =
true;
43 std::string driveName =
"diskX"; driveName[4] = char(
'a' + i);
46 throw MSXException(
"Duplicated drive name: ", driveName);
49 changer.emplace(motherBoard, driveName,
true, doubleSizedDrive,
50 [
this]() { invalidateTrack(); });
61 doSetMotor(
false, getCurrentTime());
65 const auto& driveName = changer->getDriveName();
68 unsigned driveNum = driveName[4] -
'a';
69 assert((*drivesInUse)[driveNum]);
70 (*drivesInUse)[driveNum] =
false;
75 auto typeStr = [&]() -> std::string_view {
76 if (
dynamic_cast<DummyDisk*
>(&(changer->getDisk()))) {
78 }
else if (
dynamic_cast<DirAsDSK*
>(&(changer->getDisk()))) {
88 "readonly", changer->getDisk().isWriteProtected());
89 if (
auto* disk = changer->getSectorAccessibleDisk()) {
92 return p.getResolved();
112 if (!doubleSizedDrive && (side != 0))
return false;
114 return !changer->getDisk().isDummyDisk();
121 if (signalsNeedMotorOn && !motorStatus)
return false;
122 return changer->getDisk().isWriteProtected();
127 return doubleSizedDrive ? changer->getDisk().isDoubleSided()
134 side = side_ ? 1 : 0;
142unsigned RealDrive::getMaxTrack()
const
144 constexpr unsigned MAX_TRACK = 85;
150 return MAX_TRACK * 4 + 3;
157std::optional<unsigned> RealDrive::getDiskReadTrack()
const
170 if ((headPos >= 2) && ((headPos % 4) != 2)) {
171 return (headPos - 2) / 4;
181std::optional<unsigned> RealDrive::getDiskWriteTrack()
const
188 if ((headPos >= 4) && ((headPos % 4) == 0)) {
189 return (headPos - 4) / 4;
205 if (headPos < getMaxTrack()) {
217 if (motorStatus) setLoading(time);
226 if (signalsNeedMotorOn && !motorStatus)
return false;
248 if (syncMotorTimeout.removeSyncPoint()) {
261 doSetMotor(
true, time);
268 if (syncMotorTimeout.pendingSyncPoint()) {
277 syncLoadingTimeout.removeSyncPoint();
278 loadingIndicator.
update(
false);
281 syncMotorTimeout.setSyncPoint(time + motorTimeout);
293unsigned RealDrive::getCurrentAngle(EmuTime::param time)
const
298 return narrow_cast<unsigned>((startAngle + deltaAngle) % TICKS_PER_ROTATION);
305void RealDrive::doSetMotor(
bool status, EmuTime::param time)
311 startAngle = getCurrentAngle(time);
312 motorStatus = status;
321void RealDrive::setLoading(EmuTime::param time)
324 loadingIndicator.
update(
true);
329 syncLoadingTimeout.removeSyncPoint();
333void RealDrive::execLoadingTimeout()
335 loadingIndicator.
update(
false);
338void RealDrive::execMotorTimeout(EmuTime::param time)
340 doSetMotor(
false, time);
351 return getCurrentAngle(time) < INDEX_DURATION;
357 return EmuTime::infinity();
359 unsigned delta = TICKS_PER_ROTATION - getCurrentAngle(time);
362 return time + dur1 + dur2;
365void RealDrive::invalidateTrack()
369 }
catch (MSXException&) {
375void RealDrive::getTrack()
383 if (
auto rdTrack = getDiskReadTrack()) {
384 changer->getDisk().readTrack(narrow<uint8_t>(*rdTrack),
385 narrow<uint8_t>(side),
406 track.
write(idx, val, addIdam);
413 return trackValid ? track.
read(idx) : 0;
416static constexpr unsigned divUp(
unsigned a,
unsigned b)
418 return (a + b - 1) / b;
423 unsigned currentAngle = getCurrentAngle(time);
425 unsigned idx = divUp(currentAngle * trackLen, TICKS_PER_ROTATION);
437 return EmuTime::infinity();
439 unsigned sectorAngle = divUp(sector.
addrIdx * TICKS_PER_ROTATION, trackLen);
443 auto delta = narrow<int>(sectorAngle) - narrow<int>(currentAngle);
444 if (delta < 4) delta += TICKS_PER_ROTATION;
445 assert(4 <= delta); assert(
unsigned(delta) < (TICKS_PER_ROTATION + 4));
452 if (trackValid && trackDirty) {
453 if (
auto wrTrack = getDiskWriteTrack()) {
454 changer->getDisk().writeTrack(narrow<uint8_t>(*wrTrack),
455 narrow<uint8_t>(side),
464 return changer->diskChanged();
469 return changer->peekDiskChanged();
494template<
typename Archive>
497 if (ar.versionAtLeast(version, 4)) {
498 ar.serialize(
"syncLoadingTimeout", syncLoadingTimeout,
499 "syncMotorTimeout", syncMotorTimeout);
503 ar.serialize(
"motorTimer", motorTimer,
507 "motorStatus", motorStatus);
508 if (ar.versionAtLeast(version, 3)) {
509 ar.serialize(
"startAngle", startAngle);
511 assert(Archive::IS_LOADER);
514 if (ar.versionAtLeast(version, 5)) {
515 ar.serialize(
"track", track);
516 ar.serialize(
"trackValid", trackValid);
517 ar.serialize(
"trackDirty", trackDirty);
519 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
std::shared_ptr< T > getSharedStuff(std::string_view name, Args &&...args)
Some MSX device parts are shared between several MSX devices (e.g.
CliComm & getMSXCliComm()
void registerMediaInfo(std::string_view name, MediaInfoProvider &provider)
Register and unregister providers of media info, for the media info topic.
void unregisterMediaInfo(MediaInfoProvider &provider)
LedStatus & getLedStatus()
MSXCommandController & getMSXCommandController()
void write(int idx, uint8_t val, bool setIdam=false)
uint8_t read(int idx) const
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
bool isWriteProtected() const override
Is disk write protected?
bool getMotor() const override
Returns the previously set motor status.
uint8_t readTrackByte(int idx) override
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
void setSide(bool side) override
Side select.
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
void writeTrackByte(int idx, uint8_t val, bool addIdam) override
bool isDiskInserted() const override
Is drive ready?
EmuTime getNextSector(EmuTime::param time, RawTrack::Sector §or) override
unsigned getTrackLength() override
bool getSide() const override
void getMediaInfo(TclObject &result) override
This method gets called when information is required on the media inserted in the media slot of the p...
static void restoreOld(Archive &ar, std::vector< Schedulable * > schedulables)
void addListElements(ITER first, ITER last)
void addDictKeyValue(const Key &key, const Value &value)
void addDictKeyValues(Args &&... args)
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
This file implemented 3 utility functions:
constexpr auto transform(Range &&range, UnaryOp op)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)