diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index ec2e944f5..a358de285 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -34,9 +34,10 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di colour_cycle_numerator_ = colour_cycle_numerator; phase_alternates_ = should_alternate; is_alernate_line_ &= phase_alternates_; + cycles_per_line_ = cycles_per_line; unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_; - // generate timing values implied by the given arbuments + // generate timing values implied by the given arguments sync_capacitor_charge_threshold_ = ((int)(syncCapacityLineChargeThreshold * cycles_per_line) * 3) / 4; // create the two flywheels @@ -265,16 +266,30 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo void CRT::output_scan(const Scan *const scan) { const bool this_is_sync = (scan->type == Scan::Type::Sync); - const bool is_trailing_edge = (is_receiving_sync_ && !this_is_sync); const bool is_leading_edge = (!is_receiving_sync_ && this_is_sync); is_receiving_sync_ = this_is_sync; + // Accumulate: (i) a total of the amount of time in sync; and (ii) the amount of time since sync. + if(this_is_sync) { cycles_of_sync_ += scan->number_of_cycles; cycles_since_sync_ = 0; } + else cycles_since_sync_ += scan->number_of_cycles; + + bool vsync_requested = false; + // If it has been at least half a line since sync ended, then it is safe to decide whether what ended + // was vertical sync. + if(cycles_since_sync_ > (cycles_per_line_ >> 1)) + { + // If it was vertical sync, set that flag. If it wasn't, clear the summed amount of sync to avoid + // a mistaken vertical sync due to an aggregate of horizontals. + vsync_requested = (cycles_of_sync_ > sync_capacitor_charge_threshold_); + if(vsync_requested || cycles_of_sync_ < (cycles_per_line_ >> 2)) + cycles_of_sync_ = 0; + } + // This introduces a blackout period close to the expected vertical sync point in which horizontal syncs are not // recognised, effectively causing the horizontal flywheel to freewheel during that period. This attempts to seek // the problem that vertical sync otherwise often starts halfway through a scanline, which confuses the horizontal // flywheel. I'm currently unclear whether this is an accurate solution to this problem. const bool hsync_requested = is_leading_edge && !vertical_flywheel_->is_near_expected_sync(); - const bool vsync_requested = is_trailing_edge && (sync_capacitor_charge_level_ >= sync_capacitor_charge_threshold_); // simplified colour burst logic: if it's within the back porch we'll take it if(scan->type == Scan::Type::ColourBurst) @@ -293,12 +308,6 @@ void CRT::output_scan(const Scan *const scan) sync_period_ = is_receiving_sync_ ? (sync_period_ + scan->number_of_cycles) : 0; advance_cycles(scan->number_of_cycles, hsync_requested, vsync_requested, scan->type); - - // either charge or deplete the vertical retrace capacitor (making sure it stops at 0) - if(this_is_sync) - sync_capacitor_charge_level_ += scan->number_of_cycles; - else - sync_capacitor_charge_level_ = std::max(sync_capacitor_charge_level_ - (int)scan->number_of_cycles, 0); } /* diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index ddce370be..453dbf6a5 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -94,6 +94,11 @@ class CRT { enqueued_openGL_functions_.push_back(function); } + // sync counter, for determining vertical sync + unsigned int cycles_of_sync_; + unsigned int cycles_since_sync_; + unsigned int cycles_per_line_; + public: /*! Constructs the CRT with a specified clock rate, height and colour subcarrier frequency. The requested number of buffers, each with the requested number of bytes per pixel,