diff --git a/Components/8272/i8272.hpp b/Components/8272/i8272.hpp index 6c31a9517..c8fced878 100644 --- a/Components/8272/i8272.hpp +++ b/Components/8272/i8272.hpp @@ -103,7 +103,7 @@ class i8272: public Storage::Disk::MFMController { Drive() : head_position(0), phase(NotSeeking), - drive(new Storage::Disk::Drive), + drive(new Storage::Disk::Drive(8000000, 300)), // TODO: these constants can't live here. head_is_loaded{false, false}, head_unload_delay{0, 0} {}; } drives_[4]; diff --git a/Machines/Commodore/1540/Implementation/C1540.cpp b/Machines/Commodore/1540/Implementation/C1540.cpp index a6008c51f..6f3ded472 100644 --- a/Machines/Commodore/1540/Implementation/C1540.cpp +++ b/Machines/Commodore/1540/Implementation/C1540.cpp @@ -82,7 +82,7 @@ void Machine::set_rom(const std::vector &rom) { } void Machine::set_disk(std::shared_ptr disk) { - std::shared_ptr drive(new Storage::Disk::Drive); + std::shared_ptr drive(new Storage::Disk::Drive(1000000, 300)); drive->set_disk(disk); set_drive(drive); } diff --git a/Machines/Electron/Plus3.cpp b/Machines/Electron/Plus3.cpp index 99a580e2b..e0e12bb61 100644 --- a/Machines/Electron/Plus3.cpp +++ b/Machines/Electron/Plus3.cpp @@ -16,7 +16,7 @@ Plus3::Plus3() : WD1770(P1770) { void Plus3::set_disk(std::shared_ptr disk, int drive) { if(!drives_[drive]) { - drives_[drive].reset(new Storage::Disk::Drive); + drives_[drive].reset(new Storage::Disk::Drive(8000000, 300)); if(drive == selected_drive_) set_drive(drives_[drive]); } drives_[drive]->set_disk(disk); diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index dd7cb8610..90c82cc48 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -30,7 +30,7 @@ Microdisc::Microdisc() : void Microdisc::set_disk(std::shared_ptr disk, int drive) { if(!drives_[drive]) { - drives_[drive].reset(new Storage::Disk::Drive); + drives_[drive].reset(new Storage::Disk::Drive(8000000, 300)); if(drive == selected_drive_) set_drive(drives_[drive]); } drives_[drive]->set_disk(disk); diff --git a/StaticAnalyser/Commodore/Disk.cpp b/StaticAnalyser/Commodore/Disk.cpp index 37c89c015..63221d758 100644 --- a/StaticAnalyser/Commodore/Disk.cpp +++ b/StaticAnalyser/Commodore/Disk.cpp @@ -22,7 +22,7 @@ class CommodoreGCRParser: public Storage::Disk::Controller { std::shared_ptr drive; CommodoreGCRParser() : Storage::Disk::Controller(4000000, 1, 300), shift_register_(0), track_(1) { - drive.reset(new Storage::Disk::Drive); + drive.reset(new Storage::Disk::Drive(4000000, 300)); set_drive(drive); set_motor_on(true); } diff --git a/Storage/Disk/DiskController.hpp b/Storage/Disk/DiskController.hpp index 4ab4e009c..4d35eaecc 100644 --- a/Storage/Disk/DiskController.hpp +++ b/Storage/Disk/DiskController.hpp @@ -47,7 +47,6 @@ class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop Advances the drive by @c number_of_cycles cycles. */ void run_for(const Cycles cycles); - using TimedEventLoop::run_for; /*! Sets the current drive. diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 817bdd994..f920a149a 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -11,8 +11,10 @@ using namespace Storage::Disk; -Drive::Drive() - : head_position_(0), head_(0), has_disk_(false) {} +Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute): + Storage::TimedEventLoop(input_clock_rate), + rotational_multiplier_(60, revolutions_per_minute) { +} void Drive::set_disk(const std::shared_ptr &disk) { disk_ = disk; @@ -33,7 +35,7 @@ bool Drive::has_disk() { } bool Drive::is_sleeping() { - return !has_disk_; + return !motor_is_on_ || !has_disk_; } bool Drive::get_is_track_zero() { @@ -41,8 +43,22 @@ bool Drive::get_is_track_zero() { } void Drive::step(int direction) { + int old_head_position = head_position_; head_position_ = std::max(head_position_ + direction, 0); - printf("Head -> %d\n", head_position_); + + // If the head moved and this drive has a real disk in it, flush the old track. + if(head_position_ != old_head_position && disk_ != nullptr) { + track_ = nullptr; + } +} + +Storage::Time Drive::get_time_into_track() { + // `result` will initially be amount of time since the index hole was seen as a + // proportion of a second; convert it into proportion of a rotation, simplify and return. + Time result(cycles_since_index_hole_, 8000000); + result /= rotational_multiplier_; + result.simplify(); + return result; } void Drive::set_head(unsigned int head) { @@ -68,3 +84,15 @@ std::shared_ptr Drive::get_track() { void Drive::set_track(const std::shared_ptr &track) { if(disk_) disk_->set_track_at_position(head_, (unsigned int)head_position_, track); } + +void Drive::set_motor_on(bool motor_is_on) { + motor_is_on_ = motor_is_on; + update_sleep_observer(); +} + +void Drive::process_next_event() { + if(event_delegate_) event_delegate_->process_event(current_event_); +} + +void Drive::run_for(const Cycles cycles) { +} diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index 2ed27ea71..0b45a43e8 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -13,13 +13,14 @@ #include "Disk.hpp" #include "../../ClockReceiver/Sleeper.hpp" +#include "../TimedEventLoop.hpp" namespace Storage { namespace Disk { -class Drive: public Sleeper { +class Drive: public Sleeper, public TimedEventLoop { public: - Drive(); + Drive(unsigned int input_clock_rate, int revolutions_per_minute); /*! Replaces whatever is in the drive with @c disk. @@ -72,15 +73,47 @@ class Drive: public Sleeper { */ bool get_is_ready(); + /*! + Sets whether the disk motor is on. + */ + void set_motor_on(bool); + + /*! + Advances the drive by @c number_of_cycles cycles. + */ + void run_for(const Cycles cycles); + + /*! + Provides a mechanism to receive track events as they occur. + */ + struct EventDelegate { + virtual void process_event(const Track::Event &event) = 0; + }; + + /// Sets the current event delegate. + void set_event_delegate(EventDelegate *); + // As per Sleeper. bool is_sleeping(); private: std::shared_ptr track_; std::shared_ptr disk_; - bool has_disk_; - int head_position_; - unsigned int head_; + int cycles_since_index_hole_ = 0; + Time rotational_multiplier_; + + bool has_disk_ = false; + + int head_position_ = 0; + unsigned int head_ = 0; + + void process_next_event(); + void get_next_event(const Time &duration_already_passed); + Track::Event current_event_; + bool motor_is_on_ = false; + + Time get_time_into_track(); + EventDelegate *event_delegate_ = nullptr; }; diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp index 6b69af9c1..063bdfb44 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM.cpp @@ -243,7 +243,7 @@ Parser::Parser(bool is_mfm) : bit_length.clock_rate = is_mfm ? 500000 : 250000; // i.e. 250 kbps (including clocks) set_expected_bit_length(bit_length); - drive_.reset(new Storage::Disk::Drive); + drive_.reset(new Storage::Disk::Drive(4000000, 300)); set_drive(drive_); set_motor_on(true); }