diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 25898655f..3757092e1 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -84,8 +84,10 @@ template class ConcreteMachine: speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(audio_divider))); } void update_just_in_time_cards() { - for(const auto &card : just_in_time_cards_) { - card->run_for(cycles_since_card_update_, stretched_cycles_since_card_update_); + if(cycles_since_card_update_ > Cycles(0)) { + for(const auto &card : just_in_time_cards_) { + card->run_for(cycles_since_card_update_, stretched_cycles_since_card_update_); + } } cycles_since_card_update_ = 0; stretched_cycles_since_card_update_ = 0; @@ -124,19 +126,25 @@ template class ConcreteMachine: pick_card_messaging_group(card); } - bool is_every_cycle_card(Apple::II::Card *card) { + bool is_every_cycle_card(const Apple::II::Card *card) { return !card->get_select_constraints(); } + bool card_lists_are_dirty_ = true; + bool card_became_just_in_time_ = false; void pick_card_messaging_group(Apple::II::Card *card) { + // Simplify to a card being either just-in-time or realtime. + // Don't worry about exactly what it's watching, const bool is_every_cycle = is_every_cycle_card(card); std::vector &intended = is_every_cycle ? every_cycle_cards_ : just_in_time_cards_; - std::vector &undesired = is_every_cycle ? just_in_time_cards_ : every_cycle_cards_; + // If the card is already in the proper group, stop. if(std::find(intended.begin(), intended.end(), card) != intended.end()) return; - auto old_membership = std::find(undesired.begin(), undesired.end(), card); - if(old_membership != undesired.end()) undesired.erase(old_membership); - intended.push_back(card); + + // Otherwise, mark the sets as dirty. It isn't safe to transition the card here, + // as the main loop may be part way through iterating the two lists. + card_lists_are_dirty_ = true; + card_became_just_in_time_ |= !is_every_cycle; } void card_did_change_select_constraints(Apple::II::Card *card) override { @@ -753,6 +761,31 @@ template class ConcreteMachine: } } + // Update the card lists if any mutations are due. + if(card_lists_are_dirty_) { + card_lists_are_dirty_ = false; + + // There's only one counter of time since update + // for just-in-time cards. If something new is + // transitioning, that needs to be zeroed. + if(card_became_just_in_time_) { + card_became_just_in_time_ = false; + update_just_in_time_cards(); + } + + // Clear the two lists and repopulate. + every_cycle_cards_.clear(); + just_in_time_cards_.clear(); + for(const auto &card: cards_) { + if(!card) continue; + if(is_every_cycle_card(card.get())) { + every_cycle_cards_.push_back(card.get()); + } else { + just_in_time_cards_.push_back(card.get()); + } + } + } + // Update analogue charge level. analogue_charge_ = std::min(analogue_charge_ + 1.0f / 2820.0f, 1.1f); diff --git a/Machines/Apple/AppleII/Card.hpp b/Machines/Apple/AppleII/Card.hpp index 7e68daf81..7db80b39e 100644 --- a/Machines/Apple/AppleII/Card.hpp +++ b/Machines/Apple/AppleII/Card.hpp @@ -83,10 +83,8 @@ class Card { will receive a perform_bus_operation every cycle. To reduce the number of virtual method calls, they **will not** receive run_for. run_for will propagate only to cards that register for IO and/or Device accesses only. - - */ - int get_select_constraints() { + int get_select_constraints() const { return select_constraints_; } diff --git a/Machines/Apple/AppleII/DiskIICard.cpp b/Machines/Apple/AppleII/DiskIICard.cpp index 11349e1fc..a5c721bb7 100644 --- a/Machines/Apple/AppleII/DiskIICard.cpp +++ b/Machines/Apple/AppleII/DiskIICard.cpp @@ -65,7 +65,7 @@ void DiskIICard::set_activity_observer(Activity::Observer *observer) { void DiskIICard::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) { diskii_clocking_preference_ = preference; - set_select_constraints((preference != ClockingHint::Preference::RealTime) ? (IO | Device) : 0); + set_select_constraints((preference != ClockingHint::Preference::RealTime) ? (IO | Device) : None); } Storage::Disk::Drive &DiskIICard::get_drive(int drive) { diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 8a702b568..e0068ba5d 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -20,8 +20,8 @@ using namespace Storage::Disk; Drive::Drive(int input_clock_rate, int revolutions_per_minute, int number_of_heads): Storage::TimedEventLoop(input_clock_rate), - rotational_multiplier_(60.0f / float(revolutions_per_minute)), available_heads_(number_of_heads) { + set_rotation_speed(revolutions_per_minute); const auto seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); std::default_random_engine randomiser(seed);