1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-16 05:27:43 +00:00

Merge pull request #104 from TomHarte/SyncDetection

Improves vertical sync recognition
This commit is contained in:
Thomas Harte
2017-03-06 19:18:52 -05:00
committed by GitHub
2 changed files with 27 additions and 14 deletions

View File

@@ -34,10 +34,11 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di
colour_cycle_numerator_ = colour_cycle_numerator; colour_cycle_numerator_ = colour_cycle_numerator;
phase_alternates_ = should_alternate; phase_alternates_ = should_alternate;
is_alernate_line_ &= phase_alternates_; is_alernate_line_ &= phase_alternates_;
cycles_per_line_ = cycles_per_line;
unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_; 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 * multiplied_cycles_per_line) * 3) / 4; sync_capacitor_charge_threshold_ = ((int)(syncCapacityLineChargeThreshold * cycles_per_line) * 3) / 4;
// create the two flywheels // create the two flywheels
horizontal_flywheel_.reset(new Flywheel(multiplied_cycles_per_line, (millisecondsHorizontalRetraceTime * multiplied_cycles_per_line) >> 6, multiplied_cycles_per_line >> 6)); horizontal_flywheel_.reset(new Flywheel(multiplied_cycles_per_line, (millisecondsHorizontalRetraceTime * multiplied_cycles_per_line) >> 6, multiplied_cycles_per_line >> 6));
@@ -113,7 +114,7 @@ Flywheel::SyncEvent CRT::get_next_horizontal_sync_event(bool hsync_is_requested,
#define source_phase() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 0] #define source_phase() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 0]
#define source_amplitude() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 2] #define source_amplitude() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 2]
void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type) void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const Scan::Type type)
{ {
std::unique_lock<std::mutex> output_lock = openGL_output_builder_.get_output_lock(); std::unique_lock<std::mutex> output_lock = openGL_output_builder_.get_output_lock();
number_of_cycles *= time_multiplier_; number_of_cycles *= time_multiplier_;
@@ -154,13 +155,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
// horizontal counter appropriately // horizontal counter appropriately
number_of_cycles -= next_run_length; number_of_cycles -= next_run_length;
// either charge or deplete the vertical retrace capacitor (making sure it stops at 0)
if(vsync_charging)
sync_capacitor_charge_level_ += next_run_length;
else
sync_capacitor_charge_level_ = std::max(sync_capacitor_charge_level_ - (int)next_run_length, 0);
// if(sync_capacitor_charge_level_) printf(":%c %d ", vsync_charging ? '+' : '-', sync_capacitor_charge_level_);
// react to the incoming event... // react to the incoming event...
horizontal_flywheel_->apply_event(next_run_length, (next_run_length == time_until_horizontal_sync_event) ? next_horizontal_sync_event : Flywheel::SyncEvent::None); horizontal_flywheel_->apply_event(next_run_length, (next_run_length == time_until_horizontal_sync_event) ? next_horizontal_sync_event : Flywheel::SyncEvent::None);
vertical_flywheel_->apply_event(next_run_length, (next_run_length == time_until_vertical_sync_event) ? next_vertical_sync_event : Flywheel::SyncEvent::None); vertical_flywheel_->apply_event(next_run_length, (next_run_length == time_until_vertical_sync_event) ? next_vertical_sync_event : Flywheel::SyncEvent::None);
@@ -272,16 +266,30 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
void CRT::output_scan(const Scan *const scan) void CRT::output_scan(const Scan *const scan)
{ {
const bool this_is_sync = (scan->type == Scan::Type::Sync); 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); const bool is_leading_edge = (!is_receiving_sync_ && this_is_sync);
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 // 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 // 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 // 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. // 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 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 // simplified colour burst logic: if it's within the back porch we'll take it
if(scan->type == Scan::Type::ColourBurst) if(scan->type == Scan::Type::ColourBurst)
@@ -299,7 +307,7 @@ void CRT::output_scan(const Scan *const scan)
// TODO: inspect raw data for potential colour burst if required // TODO: inspect raw data for potential colour burst if required
sync_period_ = is_receiving_sync_ ? (sync_period_ + scan->number_of_cycles) : 0; sync_period_ = is_receiving_sync_ ? (sync_period_ + scan->number_of_cycles) : 0;
advance_cycles(scan->number_of_cycles, hsync_requested, vsync_requested, this_is_sync, scan->type); advance_cycles(scan->number_of_cycles, hsync_requested, vsync_requested, scan->type);
} }
/* /*

View File

@@ -66,7 +66,7 @@ class CRT {
bool is_alernate_line_, phase_alternates_; bool is_alernate_line_, phase_alternates_;
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data // the outer entry point for dispatching output_sync, output_blank, output_level and output_data
void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type); void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const Scan::Type type);
// the inner entry point that determines whether and when the next sync event will occur within // the inner entry point that determines whether and when the next sync event will occur within
// the current output window // the current output window
@@ -94,6 +94,11 @@ class CRT {
enqueued_openGL_functions_.push_back(function); 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: public:
/*! Constructs the CRT with a specified clock rate, height and colour subcarrier frequency. /*! 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, The requested number of buffers, each with the requested number of bytes per pixel,