1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-02 20:30:00 +00:00

Made an attempt at triggering vertical sync the expected number of time after it begins, regardless of total length.

This commit is contained in:
Thomas Harte 2017-07-29 17:33:52 -04:00
parent 54bcc40192
commit 3528a7f78b
2 changed files with 48 additions and 33 deletions

View File

@ -18,7 +18,6 @@ using namespace Outputs::CRT;
void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int vertical_sync_half_lines, bool should_alternate) {
openGL_output_builder_.set_colour_format(colour_space, colour_cycle_numerator, colour_cycle_denominator);
const unsigned int syncCapacityLineChargeThreshold = 2;
const unsigned int millisecondsHorizontalRetraceTime = 7; // source: Dictionary of Video and Television Technology, p. 234
const unsigned int scanlinesVerticalRetraceTime = 10; // source: ibid
@ -37,8 +36,7 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di
cycles_per_line_ = cycles_per_line;
unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_;
// generate timing values implied by the given arguments
sync_capacitor_charge_threshold_ = ((unsigned int)(syncCapacityLineChargeThreshold * cycles_per_line) * 3) / 4;
sync_capacitor_charge_threshold_ = (vertical_sync_half_lines * cycles_per_line) >> 1;
// create the two flywheels
horizontal_flywheel_.reset(new Flywheel(multiplied_cycles_per_line, (millisecondsHorizontalRetraceTime * multiplied_cycles_per_line) >> 6, multiplied_cycles_per_line >> 6));
@ -74,7 +72,6 @@ void CRT::set_composite_function_type(CompositeSourceType type, float offset_of_
CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) :
sync_capacitor_charge_level_(0),
is_receiving_sync_(false),
sync_period_(0),
common_output_divisor_(common_output_divisor),
is_writing_composite_run_(false),
delegate_(nullptr),
@ -264,31 +261,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
#pragma mark - stream feeding methods
void CRT::output_scan(const Scan *const scan) {
const bool this_is_sync = (scan->type == Scan::Type::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();
// simplified colour burst logic: if it's within the back porch we'll take it
if(scan->type == Scan::Type::ColourBurst) {
if(!colour_burst_amplitude_ && horizontal_flywheel_->get_current_time() < (horizontal_flywheel_->get_standard_period() * 12) >> 6) {
@ -300,11 +272,54 @@ void CRT::output_scan(const Scan *const scan) {
colour_burst_phase_ = (colour_burst_phase_ & ~63) + colour_burst_phase_adjustment_;
}
}
// TODO: inspect raw data for potential colour burst if required; the DPLL and some zero crossing logic
// will probably be sufficient but some test data would be helpful
// TODO: inspect raw data for potential colour burst if required
// sync logic: mark whether this is currently sync and check for a leading edge
const bool this_is_sync = (scan->type == Scan::Type::Sync);
const bool is_leading_edge = (!is_receiving_sync_ && this_is_sync);
is_receiving_sync_ = this_is_sync;
sync_period_ = is_receiving_sync_ ? (sync_period_ + scan->number_of_cycles) : 0;
advance_cycles(scan->number_of_cycles, hsync_requested, vsync_requested, scan->type);
// horizontal sync is recognised on any leading edge that is not 'near' the expected vertical sync;
// the second limb is to avoid slightly horizontal sync shifting from the common pattern of
// equalisation pulses as the inverse of ordinary horizontal sync
bool hsync_requested = is_leading_edge && !vertical_flywheel_->is_near_expected_sync();
if(this_is_sync) {
// if this is sync then either begin or continue a sync accumulation phase
is_accumulating_sync_ = true;
} else {
// if this is not sync then check how long it has been since sync. If it's more than
// half a line then end sync accumulation and zero out the accumulating count
cycles_since_sync_ += scan->number_of_cycles;
if(cycles_since_sync_ > (cycles_per_line_ >> 1)) {
cycles_of_sync_ = 0;
is_accumulating_sync_ = false;
}
}
unsigned int number_of_cycles = scan->number_of_cycles;
bool vsync_requested = false;
// if sync is being accumulated then accumulate it; if it crosses the vertical sync threshold then
// divide this line at the crossing point and indicate vertical sync there
if(is_accumulating_sync_) {
cycles_of_sync_ += scan->number_of_cycles;
if(this_is_sync && cycles_of_sync_ >= sync_capacitor_charge_threshold_) {
unsigned int overshoot = std::max(cycles_of_sync_ - sync_capacitor_charge_threshold_, number_of_cycles);
number_of_cycles -= overshoot;
advance_cycles(number_of_cycles, hsync_requested, false, scan->type);
cycles_of_sync_ = 0;
is_accumulating_sync_ = false;
number_of_cycles = overshoot;
hsync_requested = false;
vsync_requested = true;
}
}
advance_cycles(number_of_cycles, hsync_requested, vsync_requested, scan->type);
}
/*

View File

@ -44,7 +44,6 @@ class CRT {
bool is_receiving_sync_; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync)
int sync_capacitor_charge_level_; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
unsigned int sync_capacitor_charge_threshold_; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
unsigned int sync_period_;
struct Scan {
enum Type {
@ -94,6 +93,7 @@ class CRT {
}
// sync counter, for determining vertical sync
bool is_accumulating_sync_;
unsigned int cycles_of_sync_;
unsigned int cycles_since_sync_;
unsigned int cycles_per_line_;