diff --git a/Components/DiskII/DiskII.cpp b/Components/DiskII/DiskII.cpp index e915b61a7..f2f78ac4e 100644 --- a/Components/DiskII/DiskII.cpp +++ b/Components/DiskII/DiskII.cpp @@ -211,7 +211,7 @@ void DiskII::set_disk(const std::shared_ptr &disk, int driv drives_[drive].set_disk(disk); } -void DiskII::process_event(const Storage::Disk::Track::Event &event) { +void DiskII::process_event(const Storage::Disk::Drive::Event &event) { if(event.type == Storage::Disk::Track::Event::FluxTransition) { inputs_ &= ~input_flux; flux_duration_ = 2; // Upon detection of a flux transition, the flux flag should stay set for 1us. Emulate that as two cycles. diff --git a/Components/DiskII/DiskII.hpp b/Components/DiskII/DiskII.hpp index 6df8edf10..8f5cd92f8 100644 --- a/Components/DiskII/DiskII.hpp +++ b/Components/DiskII/DiskII.hpp @@ -98,7 +98,7 @@ class DiskII: void select_drive(int drive); uint8_t trigger_address(int address, uint8_t value); - void process_event(const Storage::Disk::Track::Event &event) override; + void process_event(const Storage::Disk::Drive::Event &event) override; void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) override; const int clock_rate_ = 0; diff --git a/Components/DiskII/IWM.cpp b/Components/DiskII/IWM.cpp index 0b0d137cd..e919a9a48 100644 --- a/Components/DiskII/IWM.cpp +++ b/Components/DiskII/IWM.cpp @@ -353,7 +353,7 @@ void IWM::run_for(const Cycles cycles) { } } -void IWM::process_event(const Storage::Disk::Track::Event &event) { +void IWM::process_event(const Storage::Disk::Drive::Event &event) { switch(event.type) { case Storage::Disk::Track::Event::IndexHole: return; case Storage::Disk::Track::Event::FluxTransition: diff --git a/Components/DiskII/IWM.hpp b/Components/DiskII/IWM.hpp index e9680add2..d409b6b00 100644 --- a/Components/DiskII/IWM.hpp +++ b/Components/DiskII/IWM.hpp @@ -44,7 +44,7 @@ class IWM: private: // Storage::Disk::Drive::EventDelegate. - void process_event(const Storage::Disk::Track::Event &event) override; + void process_event(const Storage::Disk::Drive::Event &event) override; const int clock_rate_; diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 6c4782f7b..75b7e3258 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -1598,7 +1598,7 @@ template void Proces destination = (shift_count < size) ? decltype(destination)(value << shift_count) : 0; \ extend_flag_ = carry_flag_ = decltype(carry_flag_)(value) & decltype(carry_flag_)( (1u << (size - 1)) >> (shift_count - 1) ); \ \ - if(shift_count >= size) overflow_flag_ = value && (value != ((1 << size) - 1)); \ + if(shift_count >= size) overflow_flag_ = value && (value != decltype(value)(-1)); \ else { \ const auto mask = decltype(destination)((0xffffffff << (size - shift_count)) & ((1 << size) - 1)); \ overflow_flag_ = mask & value && ((mask & value) != mask); \ diff --git a/Storage/Disk/Controller/DiskController.cpp b/Storage/Disk/Controller/DiskController.cpp index 60996efde..ea4b3c056 100644 --- a/Storage/Disk/Controller/DiskController.cpp +++ b/Storage/Disk/Controller/DiskController.cpp @@ -40,7 +40,7 @@ Drive &Controller::get_drive() { // MARK: - Drive::EventDelegate -void Controller::process_event(const Track::Event &event) { +void Controller::process_event(const Drive::Event &event) { switch(event.type) { case Track::Event::FluxTransition: pll_->add_pulse(); break; case Track::Event::IndexHole: process_index_hole(); break; diff --git a/Storage/Disk/Controller/DiskController.hpp b/Storage/Disk/Controller/DiskController.hpp index c9f6a9552..7bbb07236 100644 --- a/Storage/Disk/Controller/DiskController.hpp +++ b/Storage/Disk/Controller/DiskController.hpp @@ -120,7 +120,7 @@ class Controller: void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) override; // for Drive::EventDelegate - void process_event(const Track::Event &event) override; + void process_event(const Drive::Event &event) override; void advance(const Cycles cycles) override ; // to satisfy DigitalPhaseLockedLoop::Delegate diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 7755612a6..846c15714 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -20,9 +20,8 @@ using namespace Storage::Disk; Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads): Storage::TimedEventLoop(input_clock_rate), - rotational_multiplier_(60, revolutions_per_minute), + rotational_multiplier_(60.0f / float(revolutions_per_minute)), available_heads_(number_of_heads) { - rotational_multiplier_.simplify(); const auto seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); std::default_random_engine randomiser(seed); @@ -41,7 +40,7 @@ Drive::Drive(unsigned int input_clock_rate, int number_of_heads) : Drive(input_c void Drive::set_rotation_speed(float revolutions_per_minute) { // TODO: probably I should look into // whether doing all this with quotients is really a good idea. - rotational_multiplier_ = Time(60.0f / revolutions_per_minute); + rotational_multiplier_ = 60.0f / revolutions_per_minute; } Drive::~Drive() { @@ -121,17 +120,13 @@ bool Drive::get_tachometer() { } float Drive::get_rotation() { - return get_time_into_track().get(); + return get_time_into_track(); } -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_, static_cast(get_input_clock_rate())); - result /= rotational_multiplier_; - result.simplify(); -// assert(result <= Time(1)); - return result; +float Drive::get_time_into_track() { + // i.e. amount of time since the index hole was seen, as a proportion of a second, + // converted to a proportion of a rotation. + return float(cycles_since_index_hole_) / (float(get_input_clock_rate()) * rotational_multiplier_); } bool Drive::get_is_read_only() { @@ -211,25 +206,24 @@ void Drive::run_for(const Cycles cycles) { // MARK: - Track timed event loop -void Drive::get_next_event(const Time &duration_already_passed) { +void Drive::get_next_event(float duration_already_passed) { // Grab a new track if not already in possession of one. This will recursively call get_next_event, // supplying a proper duration_already_passed. if(!track_) { - random_interval_.set_zero(); + random_interval_ = 0.0f; setup_track(); return; } // If gain has now been turned up so as to generate noise, generate some noise. - if(random_interval_ > Time(0)) { - current_event_.type = Track::Event::IndexHole; - current_event_.length.length = 2 + (random_source_&1); - current_event_.length.clock_rate = 1000000; + if(random_interval_ > 0.0f) { + current_event_.type = Track::Event::FluxTransition; + current_event_.length = float(2 + (random_source_&1)) / 1000000.0f; random_source_ = (random_source_ >> 1) | (random_source_ << 63); if(random_interval_ < current_event_.length) { current_event_.length = random_interval_; - random_interval_.set_zero(); + random_interval_ = 0.0f; } else { random_interval_ -= current_event_.length; } @@ -238,22 +232,21 @@ void Drive::get_next_event(const Time &duration_already_passed) { } if(track_) { - current_event_ = track_->get_next_event(); + const auto track_event = track_->get_next_event(); + current_event_.type = track_event.type; + current_event_.length = track_event.length.get(); } else { - current_event_.length.length = 1; - current_event_.length.clock_rate = 1; + current_event_.length = 1.0f; current_event_.type = Track::Event::IndexHole; } // divide interval, which is in terms of a single rotation of the disk, by rotation speed to // convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_ -// assert(current_event_.length <= Time(1) && current_event_.length >= Time(0)); -// assert(current_event_.length > duration_already_passed); - Time interval = (current_event_.length - duration_already_passed) * rotational_multiplier_; + float interval = std::max((current_event_.length - duration_already_passed) * rotational_multiplier_, 0.0f); // An interval greater than 15ms => adjust gain up the point where noise starts happening. // Seed that up and leave a 15ms gap until it starts. - const Time safe_gain_period(15, 1000000); + const float safe_gain_period = 15.0f / 1000000.0f; if(interval >= safe_gain_period) { random_interval_ = interval - safe_gain_period; interval = safe_gain_period; @@ -264,7 +257,6 @@ void Drive::get_next_event(const Time &duration_already_passed) { void Drive::process_next_event() { if(current_event_.type == Track::Event::IndexHole) { -// assert(get_time_into_track() == Time(1) || get_time_into_track() == Time(0)); if(ready_index_count_ < 2) ready_index_count_++; cycles_since_index_hole_ = 0; } @@ -274,7 +266,7 @@ void Drive::process_next_event() { ){ event_delegate_->process_event(current_event_); } - get_next_event(Time(0)); + get_next_event(0.0f); } // MARK: - Track management @@ -294,24 +286,20 @@ void Drive::setup_track() { track_.reset(new UnformattedTrack); } - Time offset; - Time track_time_now = get_time_into_track(); - assert(track_time_now >= Time(0) && current_event_.length <= Time(1)); + float offset = 0.0f; + const auto track_time_now = get_time_into_track(); + const auto time_found = track_->seek_to(Time(track_time_now)).get(); - Time time_found = track_->seek_to(track_time_now); - - // time_found can be greater than track_time_now if limited precision caused rounding + // `time_found` can be greater than `track_time_now` if limited precision caused rounding. if(time_found <= track_time_now) { offset = track_time_now - time_found; - } else { - offset.set_zero(); } get_next_event(offset); } void Drive::invalidate_track() { - random_interval_.set_zero(); + random_interval_ = 0.0f; track_ = nullptr; if(patched_track_) { set_track(patched_track_); @@ -328,10 +316,10 @@ void Drive::begin_writing(Time bit_length, bool clamp_to_index_hole) { cycles_per_bit_ = Storage::Time(get_input_clock_rate()) * bit_length; cycles_per_bit_.simplify(); - write_segment_.length_of_a_bit = bit_length / rotational_multiplier_; + write_segment_.length_of_a_bit = bit_length / Time(rotational_multiplier_); write_segment_.data.clear(); - write_start_time_ = get_time_into_track(); + write_start_time_ = Time(get_time_into_track()); } void Drive::write_bit(bool value) { diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index b8cc04989..62baeb042 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -105,13 +105,18 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { */ void run_for(const Cycles cycles); + struct Event { + Track::Event::Type type; + float length = 0.0f; + } current_event_; + /*! Provides a mechanism to receive track events as they occur, including the synthetic event of "you told me to output the following data, and I've done that now". */ struct EventDelegate { /// Informs the delegate that @c event has been reached. - virtual void process_event(const Track::Event &event) = 0; + virtual void process_event(const Event &event) = 0; /*! If the drive is in write mode, announces that all queued bits have now been written. @@ -175,7 +180,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { // Contains the multiplier that converts between track-relative lengths // to real-time lengths. So it's the reciprocal of rotation speed. - Time rotational_multiplier_; + float rotational_multiplier_; // A count of time since the index hole was last seen. Which is used to // determine how far the drive is into a full rotation when switching to @@ -211,12 +216,11 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { // TimedEventLoop call-ins and state. void process_next_event() override; - void get_next_event(const Time &duration_already_passed); + void get_next_event(float duration_already_passed); void advance(const Cycles cycles) override; - Track::Event current_event_; // Helper for track changes. - Time get_time_into_track(); + float get_time_into_track(); // The target (if any) for track events. EventDelegate *event_delegate_ = nullptr; @@ -241,7 +245,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { // A rotating random data source. uint64_t random_source_; - Time random_interval_; + float random_interval_; }; diff --git a/Storage/Disk/Track/Track.hpp b/Storage/Disk/Track/Track.hpp index 63d2d7207..b35d9293a 100644 --- a/Storage/Disk/Track/Track.hpp +++ b/Storage/Disk/Track/Track.hpp @@ -95,7 +95,7 @@ class Track { 1/3 away then that means 1/3 of a rotation. */ struct Event { - enum { + enum Type { IndexHole, FluxTransition } type; Time length; diff --git a/Storage/TimedEventLoop.cpp b/Storage/TimedEventLoop.cpp index b358b2758..5541bf935 100644 --- a/Storage/TimedEventLoop.cpp +++ b/Storage/TimedEventLoop.cpp @@ -65,14 +65,18 @@ void TimedEventLoop::jump_to_next_event() { } void TimedEventLoop::set_next_event_time_interval(Time interval) { + set_next_event_time_interval(interval.get()); +} + +void TimedEventLoop::set_next_event_time_interval(float interval) { // Calculate [interval]*[input clock rate] + [subcycles until this event] - double double_interval = interval.get() * static_cast(input_clock_rate_) + subcycles_until_event_; + float float_interval = interval * float(input_clock_rate_) + subcycles_until_event_; // So this event will fire in the integral number of cycles from now, putting us at the remainder // number of subcycles - const int addition = static_cast(double_interval); + const int addition = int(float_interval); cycles_until_event_ += addition; - subcycles_until_event_ = fmod(double_interval, 1.0); + subcycles_until_event_ = fmodf(float_interval, 1.0); assert(cycles_until_event_ >= 0); assert(subcycles_until_event_ >= 0.0); diff --git a/Storage/TimedEventLoop.hpp b/Storage/TimedEventLoop.hpp index ceca023ac..c3bd7ec75 100644 --- a/Storage/TimedEventLoop.hpp +++ b/Storage/TimedEventLoop.hpp @@ -64,6 +64,7 @@ namespace Storage { Sets the time interval, as a proportion of a second, until the next event should be triggered. */ void set_next_event_time_interval(Time interval); + void set_next_event_time_interval(float interval); /*! Communicates that the next event is triggered. A subclass will idiomatically process that event @@ -102,7 +103,7 @@ namespace Storage { private: unsigned int input_clock_rate_ = 0; int cycles_until_event_ = 0; - double subcycles_until_event_ = 0.0; + float subcycles_until_event_ = 0.0; }; }