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:
commit
f14d98452e
@ -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);
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -20,8 +20,8 @@ using namespace Storage::Disk;
|
|||||||
|
|
||||||
Drive::Drive(int input_clock_rate, int revolutions_per_minute, int number_of_heads):
|
Drive::Drive(int input_clock_rate, int revolutions_per_minute, int number_of_heads):
|
||||||
Storage::TimedEventLoop(input_clock_rate),
|
Storage::TimedEventLoop(input_clock_rate),
|
||||||
rotational_multiplier_(60.0f / float(revolutions_per_minute)),
|
|
||||||
available_heads_(number_of_heads) {
|
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());
|
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);
|
std::default_random_engine randomiser(seed);
|
||||||
|
Loading…
Reference in New Issue
Block a user