1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00

Merge pull request #657 from TomHarte/DiskIIAgain

Corrects time propagation for Apple II cards
This commit is contained in:
Thomas Harte 2019-09-28 23:40:07 -04:00 committed by GitHub
commit f14d98452e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 12 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)));
}
void update_just_in_time_cards() {
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 <Analyser::Static::AppleII::Target::Model model> 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<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;
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 <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.
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
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_;
}

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) {
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) {

View File

@ -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::default_random_engine::result_type>(std::chrono::system_clock::now().time_since_epoch().count());
std::default_random_engine randomiser(seed);