1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-11 04:28:58 +00:00

Started edging towards completing the CPU side of accumulating enough data for composite decoding.

This commit is contained in:
Thomas Harte 2016-03-05 17:55:18 -05:00
parent 5c8db71c64
commit 23c223e2ed
4 changed files with 135 additions and 78 deletions

View File

@ -66,9 +66,9 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes)
_run_builders = new CRTRunBuilder *[kCRTNumberOfFields]; _run_builders = new CRTRunBuilder *[kCRTNumberOfFields];
for(int builder = 0; builder < kCRTNumberOfFields; builder++) for(int builder = 0; builder < kCRTNumberOfFields; builder++)
{ {
_run_builders[builder] = new CRTRunBuilder(kCRTOutputVertexSize); _run_builders[builder] = new CRTRunBuilder(kCRTOutputVertexSize, 6);
} }
_composite_src_runs = std::unique_ptr<CRTRunBuilder>(new CRTRunBuilder(kCRTInputVertexSize)); _composite_src_runs = std::unique_ptr<CRTRunBuilder>(new CRTRunBuilder(kCRTInputVertexSize, 2));
va_list va; va_list va;
va_copy(va, sizes); va_copy(va, sizes);
@ -77,14 +77,14 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes)
} }
CRT::CRT(unsigned int common_output_divisor) : CRT::CRT(unsigned int common_output_divisor) :
_next_scan(0),
_run_write_pointer(0), _run_write_pointer(0),
_sync_capacitor_charge_level(0), _sync_capacitor_charge_level(0),
_is_receiving_sync(false), _is_receiving_sync(false),
_output_mutex(new std::mutex), _output_mutex(new std::mutex),
_visible_area(Rect(0, 0, 1, 1)), _visible_area(Rect(0, 0, 1, 1)),
_sync_period(0), _sync_period(0),
_common_output_divisor(common_output_divisor) _common_output_divisor(common_output_divisor),
_composite_src_output_y(0)
{ {
construct_openGL(); construct_openGL();
} }
@ -131,6 +131,21 @@ Flywheel::SyncEvent CRT::get_next_horizontal_sync_event(bool hsync_is_requested,
return _horizontal_flywheel->get_next_event_in_period(hsync_is_requested, cycles_to_run_for, cycles_advanced); return _horizontal_flywheel->get_next_event_in_period(hsync_is_requested, cycles_to_run_for, cycles_advanced);
} }
#define output_position_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 0])
#define output_position_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 2])
#define output_tex_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 0])
#define output_tex_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 2])
#define output_lateral(v) next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfLateral]
#define output_timestamp(v) (*(uint32_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTimestamp])
#define input_input_position_x(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfInputPosition + 0])
#define input_input_position_y(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfInputPosition + 2])
#define input_output_position_x(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfOutputPosition + 0])
#define input_output_position_y(v) (*(uint16_t *)&next_run[kCRTInputVertexSize*v + kCRTInputVertexOffsetOfOutputPosition + 2])
#define input_phase(v) next_run[kCRTOutputVertexSize*v + kCRTInputVertexOffsetOfPhaseAndAmplitude + 0]
#define input_amplitude(v) next_run[kCRTOutputVertexSize*v + kCRTInputVertexOffsetOfPhaseAndAmplitude + 1]
#define input_phase_time(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTInputVertexOffsetOfPhaseTime])
void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divider, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Type type, uint16_t tex_x, uint16_t tex_y) void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divider, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Type type, uint16_t tex_x, uint16_t tex_y)
{ {
number_of_cycles *= _time_multiplier; number_of_cycles *= _time_multiplier;
@ -150,33 +165,44 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
hsync_requested = false; hsync_requested = false;
vsync_requested = false; vsync_requested = false;
uint8_t *next_run = ((is_output_run && next_run_length) && !_horizontal_flywheel->is_in_retrace() && !_vertical_flywheel->is_in_retrace()) ? _run_builders[_run_write_pointer]->get_next_run() : nullptr; bool is_output_segment = ((is_output_run && next_run_length) && !_horizontal_flywheel->is_in_retrace() && !_vertical_flywheel->is_in_retrace());
uint8_t *next_run = nullptr;
#define position_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 0]) if(is_output_segment)
#define position_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfPosition + 2]) {
#define tex_x(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 0]) _output_mutex->lock();
#define tex_y(v) (*(uint16_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTexCoord + 2]) next_run = (_output_device == CRT::Monitor) ? _run_builders[_run_write_pointer]->get_next_run() : _composite_src_runs->get_next_run();
#define lateral(v) next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfLateral] }
#define timestamp(v) (*(uint32_t *)&next_run[kCRTOutputVertexSize*v + kCRTOutputVertexOffsetOfTimestamp])
// Vertex output is arranged as: // Vertex output is arranged as:
// //
// [0/4] 3 // [0/4] 3
// //
// 1 [2/5] // 1 [2/5]
if(next_run) if(next_run)
{ {
// set the type, initial raster position and type of this run if(_output_device == CRT::Monitor)
position_x(0) = position_x(1) = position_x(4) = (uint16_t)_horizontal_flywheel->get_current_output_position(); {
position_y(0) = position_y(1) = position_y(4) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider); // set the type, initial raster position and type of this run
timestamp(0) = timestamp(1) = timestamp(4) = _run_builders[_run_write_pointer]->duration; output_position_x(0) = output_position_x(1) = output_position_x(4) = (uint16_t)_horizontal_flywheel->get_current_output_position();
tex_x(0) = tex_x(1) = tex_x(4) = tex_x; output_position_y(0) = output_position_y(1) = output_position_y(4) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
output_timestamp(0) = output_timestamp(1) = output_timestamp(4) = _run_builders[_run_write_pointer]->duration;
output_tex_x(0) = output_tex_x(1) = output_tex_x(4) = tex_x;
// these things are constants across the line so just throw them out now // these things are constants across the line so just throw them out now
tex_y(0) = tex_y(4) = tex_y(1) = tex_y(2) = tex_y(3) = tex_y(5) = tex_y; output_tex_y(0) = output_tex_y(4) = output_tex_y(1) = output_tex_y(2) = output_tex_y(3) = output_tex_y(5) = tex_y;
lateral(0) = lateral(4) = lateral(5) = 0; output_lateral(0) = output_lateral(4) = output_lateral(5) = 0;
lateral(1) = lateral(2) = lateral(3) = 1; output_lateral(1) = output_lateral(2) = output_lateral(3) = 1;
}
else
{
input_input_position_x(0) = tex_x;
input_input_position_y(0) = input_input_position_y(1) = tex_y;
input_output_position_x(0) = (uint16_t)_horizontal_flywheel->get_current_output_position();
input_output_position_y(0) = input_output_position_y(1) = _composite_src_output_y;
input_phase(0) = input_phase(1) = _colour_burst_phase;
input_amplitude(0) = input_amplitude(1) = _colour_burst_amplitude;
input_phase_time(0) = input_phase_time(1) = _colour_burst_time;
}
} }
// decrement the number of cycles left to run for and increment the // decrement the number of cycles left to run for and increment the
@ -196,18 +222,39 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
if(next_run) if(next_run)
{ {
// store the final raster position
position_x(2) = position_x(3) = position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position();
position_y(2) = position_y(3) = position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
timestamp(2) = timestamp(3) = timestamp(5) = _run_builders[_run_write_pointer]->duration;
// if this is a data run then advance the buffer pointer // if this is a data run then advance the buffer pointer
if(type == Type::Data && source_divider) tex_x += next_run_length / (_time_multiplier * source_divider); if(type == Type::Data && source_divider) tex_x += next_run_length / (_time_multiplier * source_divider);
// if this is a data or level run then store the end point if(_output_device == CRT::Monitor)
tex_x(2) = tex_x(3) = tex_x(5) = tex_x; {
// store the final raster position
output_position_x(2) = output_position_x(3) = output_position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position();
output_position_y(2) = output_position_y(3) = output_position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
output_timestamp(2) = output_timestamp(3) = output_timestamp(5) = _run_builders[_run_write_pointer]->duration;
output_tex_x(2) = output_tex_x(3) = output_tex_x(5) = tex_x;
}
else
{
input_input_position_x(1) = tex_x;
input_output_position_x(1) = (uint16_t)_horizontal_flywheel->get_current_output_position();
}
} }
if(is_output_segment)
{
_output_mutex->unlock();
}
// if this is horizontal retrace then advance the output line counter and bookend an output run
if(_output_device == CRT::Television)
{
if(next_run_length == time_until_horizontal_sync_event && next_horizontal_sync_event == Flywheel::SyncEvent::EndRetrace)
{
_composite_src_output_y = (_composite_src_output_y + 1) % CRTIntermediateBufferHeight;
}
}
// if this is vertical retrace then adcance a field
if(next_run_length == time_until_vertical_sync_event && next_vertical_sync_event == Flywheel::SyncEvent::EndRetrace) if(next_run_length == time_until_vertical_sync_event && next_vertical_sync_event == Flywheel::SyncEvent::EndRetrace)
{ {
// TODO: how to communicate did_detect_vsync? Bring the delegate back? // TODO: how to communicate did_detect_vsync? Bring the delegate back?
@ -219,13 +266,25 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
} }
} }
#undef output_position_x
#undef output_position_y
#undef output_tex_x
#undef output_tex_y
#undef output_lateral
#undef output_timestamp
#undef input_input_position_x
#undef input_input_position_y
#undef input_output_position_x
#undef input_output_position_y
#undef input_phase
#undef input_amplitude
#undef input_phase_age
#pragma mark - stream feeding methods #pragma mark - stream feeding methods
void CRT::output_scan() void CRT::output_scan(Scan *scan)
{ {
// _next_scan ^= 1;
Scan *scan = &_scans[_next_scan];
bool this_is_sync = (scan->type == Type::Sync); bool this_is_sync = (scan->type == Type::Sync);
bool is_trailing_edge = (_is_receiving_sync && !this_is_sync); bool is_trailing_edge = (_is_receiving_sync && !this_is_sync);
bool hsync_requested = is_trailing_edge && (_sync_period < (_horizontal_flywheel->get_scan_period() >> 2)); bool hsync_requested = is_trailing_edge && (_sync_period < (_horizontal_flywheel->get_scan_period() >> 2));
@ -241,57 +300,55 @@ void CRT::output_scan()
*/ */
void CRT::output_sync(unsigned int number_of_cycles) void CRT::output_sync(unsigned int number_of_cycles)
{ {
_output_mutex->lock(); Scan scan{
_scans[_next_scan].type = Type::Sync; .type = Type::Sync,
_scans[_next_scan].number_of_cycles = number_of_cycles; .number_of_cycles = number_of_cycles
output_scan(); };
_output_mutex->unlock(); output_scan(&scan);
} }
void CRT::output_blank(unsigned int number_of_cycles) void CRT::output_blank(unsigned int number_of_cycles)
{ {
_output_mutex->lock(); Scan scan {
_scans[_next_scan].type = Type::Blank; .type = Type::Blank,
_scans[_next_scan].number_of_cycles = number_of_cycles; .number_of_cycles = number_of_cycles
output_scan(); };
_output_mutex->unlock(); output_scan(&scan);
} }
void CRT::output_level(unsigned int number_of_cycles) void CRT::output_level(unsigned int number_of_cycles)
{ {
_output_mutex->lock(); Scan scan {
_scans[_next_scan].type = Type::Level; .type = Type::Level,
_scans[_next_scan].number_of_cycles = number_of_cycles; .number_of_cycles = number_of_cycles,
_scans[_next_scan].tex_x = _buffer_builder->_write_x_position; .tex_x = _buffer_builder->_write_x_position,
_scans[_next_scan].tex_y = _buffer_builder->_write_y_position; .tex_y = _buffer_builder->_write_y_position
output_scan(); };
_output_mutex->unlock(); output_scan(&scan);
} }
void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t magnitude) void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t magnitude)
{ {
_output_mutex->lock(); Scan scan {
_scans[_next_scan].type = Type::ColourBurst; .type = Type::ColourBurst,
_scans[_next_scan].number_of_cycles = number_of_cycles; .number_of_cycles = number_of_cycles,
_scans[_next_scan].phase = phase; .phase = phase,
_scans[_next_scan].magnitude = magnitude; .magnitude = magnitude
output_scan(); };
_output_mutex->unlock(); output_scan(&scan);
} }
void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider) void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider)
{ {
_output_mutex->lock();
_buffer_builder->reduce_previous_allocation_to(number_of_cycles / source_divider); _buffer_builder->reduce_previous_allocation_to(number_of_cycles / source_divider);
_scans[_next_scan].type = Type::Data; Scan scan {
_scans[_next_scan].number_of_cycles = number_of_cycles; .type = Type::Data,
_scans[_next_scan].tex_x = _buffer_builder->_write_x_position; .number_of_cycles = number_of_cycles,
_scans[_next_scan].tex_y = _buffer_builder->_write_y_position; .tex_x = _buffer_builder->_write_x_position,
_scans[_next_scan].source_divider = source_divider; .tex_y = _buffer_builder->_write_y_position,
output_scan(); .source_divider = source_divider
};
_output_mutex->unlock(); output_scan(&scan);
} }
#pragma mark - Buffer supply #pragma mark - Buffer supply

View File

@ -292,12 +292,11 @@ class CRT {
uint8_t phase, magnitude; uint8_t phase, magnitude;
}; };
}; };
} _scans[2]; };
int _next_scan; void output_scan(Scan *scan);
void output_scan();
struct CRTRunBuilder { struct CRTRunBuilder {
CRTRunBuilder(size_t vertex_size) : _vertex_size(vertex_size) { reset(); } CRTRunBuilder(size_t vertex_size, int vertices_per_run) : _vertex_size(vertex_size), _vertices_per_run(vertices_per_run) { reset(); }
// Resets the run builder. // Resets the run builder.
void reset(); void reset();
@ -319,6 +318,7 @@ class CRT {
private: private:
size_t _vertex_size; size_t _vertex_size;
int _vertices_per_run;
}; };
struct CRTInputBufferBuilder { struct CRTInputBufferBuilder {
@ -355,7 +355,9 @@ class CRT {
// transient buffers indicating composite data not yet decoded // transient buffers indicating composite data not yet decoded
std::unique_ptr<CRTRunBuilder> _composite_src_runs; std::unique_ptr<CRTRunBuilder> _composite_src_runs;
int _composite_src_output_y; uint16_t _composite_src_output_y;
uint8_t _colour_burst_phase, _colour_burst_amplitude;
uint16_t _colour_burst_time;
// OpenGL state, kept behind an opaque pointer to avoid inclusion of the GL headers here. // OpenGL state, kept behind an opaque pointer to avoid inclusion of the GL headers here.
struct OpenGLState; struct OpenGLState;

View File

@ -88,16 +88,14 @@ void CRT::CRTRunBuilder::reset()
uint8_t *CRT::CRTRunBuilder::get_next_run() uint8_t *CRT::CRTRunBuilder::get_next_run()
{ {
const size_t vertices_per_run = 6;
// get a run from the allocated list, allocating more if we're about to overrun // get a run from the allocated list, allocating more if we're about to overrun
if((number_of_vertices + vertices_per_run) * _vertex_size >= _runs.size()) if((number_of_vertices + (size_t)_vertices_per_run) * _vertex_size >= _runs.size())
{ {
_runs.resize(_runs.size() + _vertex_size * vertices_per_run * 100); _runs.resize(_runs.size() + _vertex_size * (size_t)_vertices_per_run * 100);
} }
uint8_t *next_run = &_runs[number_of_vertices * _vertex_size]; uint8_t *next_run = &_runs[number_of_vertices * _vertex_size];
number_of_vertices += vertices_per_run; number_of_vertices += (size_t)_vertices_per_run;
return next_run; return next_run;
} }

View File

@ -23,7 +23,7 @@ const size_t kCRTOutputVertexSize = 16;
const size_t kCRTInputVertexOffsetOfInputPosition = 0; const size_t kCRTInputVertexOffsetOfInputPosition = 0;
const size_t kCRTInputVertexOffsetOfOutputPosition = 4; const size_t kCRTInputVertexOffsetOfOutputPosition = 4;
const size_t kCRTInputVertexOffsetOfPhaseAndAmplitude = 8; const size_t kCRTInputVertexOffsetOfPhaseAndAmplitude = 8;
const size_t kCRTInputVertexOffsetOfPhaseAge = 12; const size_t kCRTInputVertexOffsetOfPhaseTime = 12;
const size_t kCRTInputVertexSize = 16; const size_t kCRTInputVertexSize = 16;