mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-03 22:33:29 +00:00
Explicitly separated vertical and horizontal sync event tracking, so as explicitly to be able to handle a coincidental simultaneous occurrence of both. Also for clarity.
This commit is contained in:
parent
529f61caa1
commit
33c06baffa
160
Outputs/CRT.cpp
160
Outputs/CRT.cpp
@ -75,17 +75,8 @@ CRT::~CRT()
|
||||
|
||||
#pragma mark - Sync loop
|
||||
|
||||
CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsync_is_charging, int cycles_to_run_for, int *cycles_advanced)
|
||||
CRT::SyncEvent CRT::next_vertical_sync_event(bool vsync_is_charging, int cycles_to_run_for, int *cycles_advanced)
|
||||
{
|
||||
// do we recognise this hsync, thereby adjusting time expectations?
|
||||
if ((_horizontal_counter < _hsync_error_window || _horizontal_counter >= _expected_next_hsync - _hsync_error_window) && hsync_is_requested) {
|
||||
_did_detect_hsync = true;
|
||||
|
||||
int time_now = (_horizontal_counter < _hsync_error_window) ? _expected_next_hsync + _horizontal_counter : _horizontal_counter;
|
||||
_expected_next_hsync = (_expected_next_hsync + time_now) >> 1;
|
||||
// printf("to %d for %d\n", _expected_next_hsync, time_now);
|
||||
}
|
||||
|
||||
SyncEvent proposedEvent = SyncEvent::None;
|
||||
int proposedSyncTime = cycles_to_run_for;
|
||||
|
||||
@ -99,18 +90,6 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
|
||||
}
|
||||
}
|
||||
|
||||
// will we end an ongoing hsync?
|
||||
if (_horizontal_counter < _horizontal_retrace_time && _horizontal_counter+proposedSyncTime >= _horizontal_retrace_time) {
|
||||
proposedSyncTime = _horizontal_retrace_time - _horizontal_counter;
|
||||
proposedEvent = SyncEvent::EndHSync;
|
||||
}
|
||||
|
||||
// will we start an hsync?
|
||||
if (_horizontal_counter + proposedSyncTime >= _expected_next_hsync) {
|
||||
proposedSyncTime = _expected_next_hsync - _horizontal_counter;
|
||||
proposedEvent = SyncEvent::StartHSync;
|
||||
}
|
||||
|
||||
// will an acceptable vertical sync be triggered?
|
||||
if (vsync_is_charging && !_vretrace_counter) {
|
||||
if (_sync_capacitor_charge_level < _sync_capacitor_charge_threshold && _sync_capacitor_charge_level + proposedSyncTime >= _sync_capacitor_charge_threshold) {
|
||||
@ -131,6 +110,35 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
|
||||
return proposedEvent;
|
||||
}
|
||||
|
||||
CRT::SyncEvent CRT::next_horizontal_sync_event(bool hsync_is_requested, int cycles_to_run_for, int *cycles_advanced)
|
||||
{
|
||||
// do we recognise this hsync, thereby adjusting future time expectations?
|
||||
if ((_horizontal_counter < _hsync_error_window || _horizontal_counter >= _expected_next_hsync - _hsync_error_window) && hsync_is_requested) {
|
||||
_did_detect_hsync = true;
|
||||
|
||||
int time_now = (_horizontal_counter < _hsync_error_window) ? _expected_next_hsync + _horizontal_counter : _horizontal_counter;
|
||||
_expected_next_hsync = (_expected_next_hsync + time_now) >> 1;
|
||||
}
|
||||
|
||||
SyncEvent proposedEvent = SyncEvent::None;
|
||||
int proposedSyncTime = cycles_to_run_for;
|
||||
|
||||
// will we end an ongoing hsync?
|
||||
if (_horizontal_counter < _horizontal_retrace_time && _horizontal_counter+proposedSyncTime >= _horizontal_retrace_time) {
|
||||
proposedSyncTime = _horizontal_retrace_time - _horizontal_counter;
|
||||
proposedEvent = SyncEvent::EndHSync;
|
||||
}
|
||||
|
||||
// will we start an hsync?
|
||||
if (_horizontal_counter + proposedSyncTime >= _expected_next_hsync) {
|
||||
proposedSyncTime = _expected_next_hsync - _horizontal_counter;
|
||||
proposedEvent = SyncEvent::StartHSync;
|
||||
}
|
||||
|
||||
*cycles_advanced = proposedSyncTime;
|
||||
return proposedEvent;
|
||||
}
|
||||
|
||||
void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool vsync_charging, const CRTRun::Type type, const char *data_type)
|
||||
{
|
||||
// this is safe to keep locally because it accumulates over this run of cycles only
|
||||
@ -138,16 +146,19 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
|
||||
|
||||
while(number_of_cycles) {
|
||||
|
||||
// get the next sync event and its timing; hsync request is instantaneous (being edge triggered) so
|
||||
// set it to false for the next run through this loop (if any)
|
||||
int next_run_length;
|
||||
SyncEvent next_event = advance_to_next_sync_event(hsync_requested, vsync_charging, number_of_cycles, &next_run_length);
|
||||
int time_until_vertical_sync_event, time_until_horizontal_sync_event;
|
||||
SyncEvent next_vertical_sync_event = this->next_vertical_sync_event(vsync_charging, number_of_cycles, &time_until_vertical_sync_event);
|
||||
SyncEvent next_horizontal_sync_event = this->next_horizontal_sync_event(hsync_requested, time_until_vertical_sync_event, &time_until_horizontal_sync_event);
|
||||
hsync_requested = false;
|
||||
|
||||
if(_current_frame)
|
||||
{
|
||||
CRTRun *nextRun = _current_frame->get_next_run();
|
||||
// get the next sync event and its timing; hsync request is instantaneous (being edge triggered) so
|
||||
// set it to false for the next run through this loop (if any)
|
||||
int next_run_length = std::min(time_until_vertical_sync_event, time_until_horizontal_sync_event);
|
||||
|
||||
CRTRun *nextRun = (_current_frame && next_run_length) ? _current_frame->get_next_run() : nullptr;
|
||||
|
||||
if(nextRun)
|
||||
{
|
||||
// set the type, initial raster position and type of this run
|
||||
nextRun->type = type;
|
||||
nextRun->start_point.dst_x = _rasterPosition.x;
|
||||
@ -205,52 +216,63 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
|
||||
_vretrace_counter = std::max(_vretrace_counter - next_run_length, 0);
|
||||
|
||||
// react to the incoming event...
|
||||
switch(next_event) {
|
||||
if(next_run_length == time_until_horizontal_sync_event)
|
||||
{
|
||||
switch(next_horizontal_sync_event)
|
||||
{
|
||||
// start of hsync: zero the scanline counter, note that we're now in
|
||||
// horizontal sync, increment the lines-in-this-frame counter
|
||||
case SyncEvent::StartHSync:
|
||||
_horizontal_counter = 0;
|
||||
_is_in_hsync = true;
|
||||
break;
|
||||
|
||||
// start of hsync: zero the scanline counter, note that we're now in
|
||||
// horizontal sync, increment the lines-in-this-frame counter
|
||||
case SyncEvent::StartHSync:
|
||||
_horizontal_counter = 0;
|
||||
_is_in_hsync = true;
|
||||
break;
|
||||
// end of horizontal sync: update the flywheel's velocity, note that we're no longer
|
||||
// in horizontal sync
|
||||
case SyncEvent::EndHSync:
|
||||
if (!_did_detect_hsync) {
|
||||
_expected_next_hsync = (_expected_next_hsync + (_hsync_error_window >> 1) + _cycles_per_line) >> 1;
|
||||
}
|
||||
_did_detect_hsync = false;
|
||||
_is_in_hsync = false;
|
||||
break;
|
||||
|
||||
// end of horizontal sync: update the flywheel's velocity, note that we're no longer
|
||||
// in horizontal sync
|
||||
case SyncEvent::EndHSync:
|
||||
if (!_did_detect_hsync) {
|
||||
_expected_next_hsync = (_expected_next_hsync + (_hsync_error_window >> 1) + _cycles_per_line) >> 1;
|
||||
}
|
||||
_did_detect_hsync = false;
|
||||
_is_in_hsync = false;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// start of vertical sync: reset the lines-in-this-frame counter,
|
||||
// load the retrace counter with the amount of time it'll take to retrace
|
||||
case SyncEvent::StartVSync:
|
||||
_vretrace_counter = _vertical_retrace_time;
|
||||
break;
|
||||
if(next_run_length == time_until_vertical_sync_event)
|
||||
{
|
||||
switch(next_vertical_sync_event)
|
||||
{
|
||||
// start of vertical sync: reset the lines-in-this-frame counter,
|
||||
// load the retrace counter with the amount of time it'll take to retrace
|
||||
case SyncEvent::StartVSync:
|
||||
_vretrace_counter = _vertical_retrace_time;
|
||||
break;
|
||||
|
||||
// end of vertical sync: tell the delegate that we finished vertical sync,
|
||||
// releasing all runs back into the common pool
|
||||
case SyncEvent::EndVSync:
|
||||
if(_delegate && _current_frame)
|
||||
{
|
||||
_current_frame->complete();
|
||||
_frames_with_delegate++;
|
||||
_delegate->crt_did_end_frame(this, _current_frame);
|
||||
}
|
||||
// end of vertical sync: tell the delegate that we finished vertical sync,
|
||||
// releasing all runs back into the common pool
|
||||
case SyncEvent::EndVSync:
|
||||
if(_delegate && _current_frame)
|
||||
{
|
||||
_current_frame->complete();
|
||||
_frames_with_delegate++;
|
||||
_delegate->crt_did_end_frame(this, _current_frame);
|
||||
}
|
||||
|
||||
if(_frames_with_delegate < kCRTNumberOfFrames)
|
||||
{
|
||||
_frame_read_pointer = (_frame_read_pointer + 1)%kCRTNumberOfFrames;
|
||||
_current_frame = _frames[_frame_read_pointer];
|
||||
_current_frame->reset();
|
||||
}
|
||||
else
|
||||
_current_frame = nullptr;
|
||||
break;
|
||||
if(_frames_with_delegate < kCRTNumberOfFrames)
|
||||
{
|
||||
_frame_read_pointer = (_frame_read_pointer + 1)%kCRTNumberOfFrames;
|
||||
_current_frame = _frames[_frame_read_pointer];
|
||||
_current_frame->reset();
|
||||
}
|
||||
else
|
||||
_current_frame = nullptr;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +132,8 @@ class CRT {
|
||||
StartHSync, EndHSync,
|
||||
StartVSync, EndVSync
|
||||
};
|
||||
SyncEvent advance_to_next_sync_event(bool hsync_is_requested, bool vsync_is_charging, int cycles_to_run_for, int *cycles_advanced);
|
||||
SyncEvent next_vertical_sync_event(bool vsync_is_charging, int cycles_to_run_for, int *cycles_advanced);
|
||||
SyncEvent next_horizontal_sync_event(bool hsync_is_requested, int cycles_to_run_for, int *cycles_advanced);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user