1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-02 02:49:28 +00:00

Seeks to ensure that card transitions between real-time and just-in-time don't break timing.

This commit is contained in:
Thomas Harte 2019-09-28 18:34:04 -04:00
parent c089d1cd09
commit 4ac3839185
3 changed files with 42 additions and 11 deletions

View File

@ -84,9 +84,11 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(audio_divider))); speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(audio_divider)));
} }
void update_just_in_time_cards() { void update_just_in_time_cards() {
if(cycles_since_card_update_ > Cycles(0)) {
for(const auto &card : just_in_time_cards_) { for(const auto &card : just_in_time_cards_) {
card->run_for(cycles_since_card_update_, stretched_cycles_since_card_update_); card->run_for(cycles_since_card_update_, stretched_cycles_since_card_update_);
} }
}
cycles_since_card_update_ = 0; cycles_since_card_update_ = 0;
stretched_cycles_since_card_update_ = 0; stretched_cycles_since_card_update_ = 0;
} }
@ -124,19 +126,25 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
pick_card_messaging_group(card); 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(); 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) { 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); const bool is_every_cycle = is_every_cycle_card(card);
std::vector<Apple::II::Card *> &intended = is_every_cycle ? every_cycle_cards_ : just_in_time_cards_; std::vector<Apple::II::Card *> &intended = is_every_cycle ? every_cycle_cards_ : just_in_time_cards_;
std::vector<Apple::II::Card *> &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; 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); // Otherwise, mark the sets as dirty. It isn't safe to transition the card here,
intended.push_back(card); // 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 { void card_did_change_select_constraints(Apple::II::Card *card) override {
@ -753,6 +761,31 @@ template <Analyser::Static::AppleII::Target::Model model> 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. // Update analogue charge level.
analogue_charge_ = std::min(analogue_charge_ + 1.0f / 2820.0f, 1.1f); analogue_charge_ = std::min(analogue_charge_ + 1.0f / 2820.0f, 1.1f);

View File

@ -83,10 +83,8 @@ class Card {
will receive a perform_bus_operation every cycle. To reduce the number of 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 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. only to cards that register for IO and/or Device accesses only.
*/ */
int get_select_constraints() { int get_select_constraints() const {
return select_constraints_; return select_constraints_;
} }

View File

@ -65,7 +65,7 @@ void DiskIICard::set_activity_observer(Activity::Observer *observer) {
void DiskIICard::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) { void DiskIICard::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) {
diskii_clocking_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) { Storage::Disk::Drive &DiskIICard::get_drive(int drive) {