1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-27 00:30:26 +00:00

Merge pull request #1455 from TomHarte/MatchBefore

Restructure loop to perform events AT time, not upon reaching it.
This commit is contained in:
Thomas Harte 2025-01-12 19:18:32 -05:00 committed by GitHub
commit 61086d5360
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -223,6 +223,148 @@ public:
subcycles_ += cycles * 2;
auto ticks_remaining = subcycles_.divide(is_ntsc_ ? Cycles(4) : Cycles(5)).as<int>();
while(ticks_remaining) {
//
// Check for events: (i) deferred; ...
//
if(delayed_events_) {
if(delayed_events_ & uint64_t(DelayedEvent::Latch)) {
if(char_pos_latch_ && vertical_sub_active_) {
character_position_reload_ = character_position_;
}
char_pos_latch_ = vertical_sub_count_ == 6;
if(char_pos_latch_ && enable_display_) {
video_counter_reload_ = video_counter_;
}
}
if(delayed_events_ & uint64_t(DelayedEvent::Flash)) {
if(vertical_counter_ == 205) {
++flash_count_;
flash_mask_ = (flash_count_ & 0x10) ? 0xff : 0x00;
}
}
if(delayed_events_ & uint64_t(DelayedEvent::IncrementVerticalLine)) {
vertical_counter_ = next_vertical_counter_;
bad_line2_ = bad_line();
}
if(delayed_events_ & uint64_t(DelayedEvent::IncrementVerticalSub)) {
if(!video_line_) {
vertical_sub_count_ = 7; // TODO: should be between cycle 0xc8 and 0xca?
} else if(display_enable_ && vertical_sub_active_) {
vertical_sub_count_ = (vertical_sub_count_ + 1) & 7;
}
}
if(delayed_events_ & uint64_t(DelayedEvent::CounterReset)) {
horizontal_counter_ = 0;
}
delayed_events_ &= ~uint64_t(DelayedEvent::Mask);
}
// ... (ii) timer-linked.
switch(HorizontalEvent(horizontal_counter_)) {
case HorizontalEvent::CounterOverflow:
horizontal_counter_ = 0;
[[fallthrough]];
case HorizontalEvent::Begin40Columns:
if(vertical_screen_ && enable_display_) wide_screen_ = true;
break;
case HorizontalEvent::End40Columns:
if(vertical_screen_ && enable_display_) wide_screen_ = false;
break;
case HorizontalEvent::Begin38Columns:
if(vertical_screen_ && enable_display_) narrow_screen_ = true;
break;
case HorizontalEvent::End38Columns:
if(vertical_screen_ && enable_display_) narrow_screen_ = false;
video_shift_ = false;
break;
case HorizontalEvent::DMAWindowEnd: dma_window_ = false; break;
case HorizontalEvent::EndRefresh: refresh_ = false; break;
case HorizontalEvent::EndCharacterFetchWindow: character_window_ = false; break;
case HorizontalEvent::BeginBlank: horizontal_blank_ = true; break;
case HorizontalEvent::BeginSync: horizontal_sync_ = true; break;
case HorizontalEvent::EndSync: horizontal_sync_ = false; break;
case HorizontalEvent::LatchCharacterPosition: schedule<8>(DelayedEvent::Latch); break;
case HorizontalEvent::IncrementFlashCounter: schedule<4>(DelayedEvent::Flash); break;
case HorizontalEvent::EndOfScreen:
schedule<8>(DelayedEvent::IncrementVerticalLine);
next_vertical_counter_ = video_line_ == eos() ? 0 : ((vertical_counter_ + 1) & 511);
horizontal_burst_ = true;
break;
case HorizontalEvent::EndExternalFetchWindow:
external_fetch_ = false;
increment_character_position_ = false;
if(enable_display_) increment_video_counter_ = false;
refresh_ = true;
break;
case HorizontalEvent::VerticalSubActive:
if(bad_line()) {
vertical_sub_active_ = true;
} else if(!enable_display_) {
vertical_sub_active_ = false;
}
break;
case HorizontalEvent::IncrementVerticalSub:
schedule<8>(DelayedEvent::IncrementVerticalSub);
video_line_ = vertical_counter_;
character_position_ = 0;
if(video_line_ == eos()) {
character_position_reload_ = 0;
video_counter_reload_ = 0;
}
break;
case HorizontalEvent::ScheduleCounterReset:
schedule<1>(DelayedEvent::CounterReset);
break;
case HorizontalEvent::BeginExternalFetchClock:
external_fetch_ = true;
if(video_line_ == vs_start()) {
vertical_sync_ = true;
} else if(video_line_ == vs_stop()) {
vertical_sync_ = false;
}
break;
case HorizontalEvent::BeginAttributeFetch:
dma_window_ = true;
horizontal_burst_ = false; // Should be 1 cycle later, if the data sheet is completely accurate.
// Though all other timings work on the assumption that it isn't.
break;
case HorizontalEvent::EndBlank:
horizontal_blank_ = false;
break;
case HorizontalEvent::IncrementVideoCounter:
increment_character_position_ = true;
if(enable_display_) increment_video_counter_ = true;
if(enable_display_ && vertical_sub_active_) {
character_position_ = character_position_reload_;
}
video_counter_ = video_counter_reload_;
break;
case HorizontalEvent::BeginShiftRegister:
if(enable_display_) {
character_window_ = video_shift_ = true;
}
output_.reset();
break;
}
// Test for raster interrupt.
if(raster_interrupt_ == vertical_counter_) {
if(!raster_interrupt_done_) {
@ -435,155 +577,11 @@ public:
}
}
}
// Advance for the current period.
time_in_state_ += period;
//
// Advance for current period, then check for...
//
horizontal_counter_ += period;
// ... deferred events, and...
if(delayed_events_) {
delayed_events_ >>= period * DelayEventSize;
if(delayed_events_ & uint64_t(DelayedEvent::Latch)) {
if(char_pos_latch_ && vertical_sub_active_) {
character_position_reload_ = character_position_;
}
char_pos_latch_ = vertical_sub_count_ == 6;
if(char_pos_latch_ && enable_display_) {
video_counter_reload_ = video_counter_;
}
}
if(delayed_events_ & uint64_t(DelayedEvent::Flash)) {
if(vertical_counter_ == 205) {
++flash_count_;
flash_mask_ = (flash_count_ & 0x10) ? 0xff : 0x00;
}
}
if(delayed_events_ & uint64_t(DelayedEvent::IncrementVerticalLine)) {
vertical_counter_ = next_vertical_counter_;
bad_line2_ = bad_line();
}
if(delayed_events_ & uint64_t(DelayedEvent::IncrementVerticalSub)) {
if(!video_line_) {
vertical_sub_count_ = 7; // TODO: should be between cycle 0xc8 and 0xca?
} else if(display_enable_ && vertical_sub_active_) {
vertical_sub_count_ = (vertical_sub_count_ + 1) & 7;
}
}
if(delayed_events_ & uint64_t(DelayedEvent::CounterReset)) {
horizontal_counter_ = 0;
}
delayed_events_ &= ~uint64_t(DelayedEvent::Mask);
}
// ... timer-linked events.
switch(HorizontalEvent(horizontal_counter_)) {
case HorizontalEvent::CounterOverflow:
horizontal_counter_ = 0;
[[fallthrough]];
case HorizontalEvent::Begin40Columns:
if(vertical_screen_ && enable_display_) wide_screen_ = true;
break;
case HorizontalEvent::End40Columns:
if(vertical_screen_ && enable_display_) wide_screen_ = false;
break;
case HorizontalEvent::Begin38Columns:
if(vertical_screen_ && enable_display_) narrow_screen_ = true;
break;
case HorizontalEvent::End38Columns:
if(vertical_screen_ && enable_display_) narrow_screen_ = false;
video_shift_ = false;
break;
case HorizontalEvent::DMAWindowEnd: dma_window_ = false; break;
case HorizontalEvent::EndRefresh: refresh_ = false; break;
case HorizontalEvent::EndCharacterFetchWindow: character_window_ = false; break;
case HorizontalEvent::BeginBlank: horizontal_blank_ = true; break;
case HorizontalEvent::BeginSync: horizontal_sync_ = true; break;
case HorizontalEvent::EndSync: horizontal_sync_ = false; break;
case HorizontalEvent::LatchCharacterPosition: schedule<8>(DelayedEvent::Latch); break;
case HorizontalEvent::IncrementFlashCounter: schedule<4>(DelayedEvent::Flash); break;
case HorizontalEvent::EndOfScreen:
schedule<8>(DelayedEvent::IncrementVerticalLine);
next_vertical_counter_ = video_line_ == eos() ? 0 : ((vertical_counter_ + 1) & 511);
horizontal_burst_ = true;
break;
case HorizontalEvent::EndExternalFetchWindow:
external_fetch_ = false;
increment_character_position_ = false;
if(enable_display_) increment_video_counter_ = false;
refresh_ = true;
break;
case HorizontalEvent::VerticalSubActive:
if(bad_line()) {
vertical_sub_active_ = true;
} else if(!enable_display_) {
vertical_sub_active_ = false;
}
break;
case HorizontalEvent::IncrementVerticalSub:
schedule<8>(DelayedEvent::IncrementVerticalSub);
video_line_ = vertical_counter_;
character_position_ = 0;
if(video_line_ == eos()) {
character_position_reload_ = 0;
video_counter_reload_ = 0;
}
break;
case HorizontalEvent::ScheduleCounterReset:
schedule<1>(DelayedEvent::CounterReset);
break;
case HorizontalEvent::BeginExternalFetchClock:
external_fetch_ = true;
if(video_line_ == vs_start()) {
vertical_sync_ = true;
} else if(video_line_ == vs_stop()) {
vertical_sync_ = false;
}
break;
case HorizontalEvent::BeginAttributeFetch:
dma_window_ = true;
horizontal_burst_ = false; // Should be 1 cycle later, if the data sheet is completely accurate.
// Though all other timings work on the assumption that it isn't.
break;
case HorizontalEvent::EndBlank:
horizontal_blank_ = false;
break;
case HorizontalEvent::IncrementVideoCounter:
increment_character_position_ = true;
if(enable_display_) increment_video_counter_ = true;
if(enable_display_ && vertical_sub_active_) {
character_position_ = character_position_reload_;
}
video_counter_ = video_counter_reload_;
break;
case HorizontalEvent::BeginShiftRegister:
if(enable_display_) {
character_window_ = video_shift_ = true;
}
output_.reset();
break;
}
delayed_events_ >>= period * DelayEventSize;
ticks_remaining -= period;
}
}