From 20cab08f8f480deea45af737b4d4a942b00b123a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 23 Jan 2016 17:44:34 -0500 Subject: [PATCH] Added a two-slot buffer of scans and a comon dispatch mechanism. --- Outputs/CRT.cpp | 75 +++++++++++++++++++++++++++++++------------------ Outputs/CRT.hpp | 19 ++++++++++++- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/Outputs/CRT.cpp b/Outputs/CRT.cpp index 307be6caa..9e5b73204 100644 --- a/Outputs/CRT.cpp +++ b/Outputs/CRT.cpp @@ -64,7 +64,16 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di } } -CRT::CRT(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int number_of_buffers, ...) +CRT::CRT(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int number_of_buffers, ...) : + _next_scan(0), + _frames_with_delegate(0), + _frame_read_pointer(0), + _horizontal_counter(0), + _sync_capacitor_charge_level(0), + _is_receiving_sync(false), + _is_in_hsync(false), + _is_in_vsync(false), + _rasterPosition({.x = 0, .y = 0}) { set_new_timing(cycles_per_line, height_of_display); @@ -79,24 +88,10 @@ CRT::CRT(unsigned int cycles_per_line, unsigned int height_of_display, unsigned _frame_builders[frame] = new CRTFrameBuilder(bufferWidth, bufferHeight, number_of_buffers, va); va_end(va); } - _frames_with_delegate = 0; - _frame_read_pointer = 0; _current_frame_builder = _frame_builders[0]; - // reset raster position - _rasterPosition.x = _rasterPosition.y = 0; - // reset flywheel sync _expected_next_hsync = _cycles_per_line; - _horizontal_counter = 0; - - // reset the vertical charge capacitor - _sync_capacitor_charge_level = 0; - - // start off not in horizontal sync, not receiving a sync signal - _is_receiving_sync = false; - _is_in_hsync = false; - _is_in_vsync = false; } CRT::~CRT() @@ -349,35 +344,61 @@ void CRT::set_delegate(Delegate *delegate) #pragma mark - stream feeding methods +void CRT::output_scan(Scan *scan) +{ + bool this_is_sync = (scan->type == Type::Sync); + bool hsync_requested = !_is_receiving_sync && this_is_sync; + bool vsync_requested = _is_receiving_sync; + _is_receiving_sync = this_is_sync; + + advance_cycles(scan->number_of_cycles, scan->source_divider, hsync_requested, vsync_requested, this_is_sync, scan->type); + + _next_scan ^= 1; +} + /* These all merely channel into advance_cycles, supplying appropriate arguments */ void CRT::output_sync(unsigned int number_of_cycles) { - bool _hsync_requested = !_is_receiving_sync; // ensure this really is edge triggered; someone calling output_sync twice in succession shouldn't trigger it twice - _is_receiving_sync = true; - advance_cycles(number_of_cycles, 1, _hsync_requested, false, true, Type::Sync); + _scans[_next_scan].type = Type::Sync; + _scans[_next_scan].number_of_cycles = number_of_cycles; + output_scan(&_scans[_next_scan]); } void CRT::output_blank(unsigned int number_of_cycles) { - bool _vsync_requested = _is_receiving_sync; - _is_receiving_sync = false; - advance_cycles(number_of_cycles, 1, false, _vsync_requested, false, Type::Blank); + _scans[_next_scan].type = Type::Blank; + _scans[_next_scan].number_of_cycles = number_of_cycles; + output_scan(&_scans[_next_scan]); } void CRT::output_level(unsigned int number_of_cycles) { - bool _vsync_requested = _is_receiving_sync; - _is_receiving_sync = false; - advance_cycles(number_of_cycles, 1, false, _vsync_requested, false, Type::Level); + _scans[_next_scan].type = Type::Level; + _scans[_next_scan].number_of_cycles = number_of_cycles; + _scans[_next_scan].tex_x = _current_frame_builder ? _current_frame_builder->_write_x_position : 0; + _scans[_next_scan].tex_y = _current_frame_builder ? _current_frame_builder->_write_y_position : 0; + output_scan(&_scans[_next_scan]); +} + +void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t magnitude) +{ + _scans[_next_scan].type = Type::ColourBurst; + _scans[_next_scan].number_of_cycles = number_of_cycles; + _scans[_next_scan].phase = phase; + _scans[_next_scan].magnitude = magnitude; + output_scan(&_scans[_next_scan]); } void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider) { - bool _vsync_requested = _is_receiving_sync; - _is_receiving_sync = false; - advance_cycles(number_of_cycles, source_divider, false, _vsync_requested, false, Type::Data); + _scans[_next_scan].type = Type::Data; + _scans[_next_scan].number_of_cycles = number_of_cycles; + _scans[_next_scan].tex_x = _current_frame_builder ? _current_frame_builder->_write_x_position : 0; + _scans[_next_scan].tex_y = _current_frame_builder ? _current_frame_builder->_write_y_position : 0; + _scans[_next_scan].source_divider = source_divider; + output_scan(&_scans[_next_scan]); } #pragma mark - Buffer supply diff --git a/Outputs/CRT.hpp b/Outputs/CRT.hpp index af87c4f29..865e9dda7 100644 --- a/Outputs/CRT.hpp +++ b/Outputs/CRT.hpp @@ -144,7 +144,7 @@ class CRT { // the outer entry point for dispatching output_sync, output_blank, output_level and output_data enum Type { - Sync, Level, Data, Blank + Sync, Level, Data, Blank, ColourBurst } type; void advance_cycles(unsigned int number_of_cycles, unsigned int source_divider, bool hsync_requested, bool vsync_requested, bool vsync_charging, Type type); @@ -157,6 +157,23 @@ class CRT { }; SyncEvent get_next_vertical_sync_event(bool vsync_is_requested, unsigned int cycles_to_run_for, unsigned int *cycles_advanced); SyncEvent get_next_horizontal_sync_event(bool hsync_is_requested, unsigned int cycles_to_run_for, unsigned int *cycles_advanced); + + // each call to output_* generates a scan. A two-slot queue for scans allows edge extensions. + struct Scan { + Type type; + unsigned int number_of_cycles; + union { + struct { + unsigned int source_divider; + uint16_t tex_x, tex_y; + }; + struct { + uint8_t phase, magnitude; + }; + }; + } _scans[2]; + int _next_scan; + void output_scan(Scan *scan); }; }