2015-07-19 17:36:27 +00:00
//
// CRT.hpp
// Clock Signal
//
// Created by Thomas Harte on 19/07/2015.
// Copyright © 2015 Thomas Harte. All rights reserved.
//
# ifndef CRT_cpp
# define CRT_cpp
# include <stdint.h>
2015-07-23 00:33:20 +00:00
# include <stdarg.h>
2015-07-19 17:36:27 +00:00
# include <string>
2015-07-21 03:18:56 +00:00
# include <vector>
2015-07-19 17:36:27 +00:00
2015-07-25 03:29:45 +00:00
# include "CRTFrame.h"
2015-07-23 00:33:20 +00:00
2015-07-25 03:29:45 +00:00
namespace Outputs {
2015-07-23 00:33:20 +00:00
class CRT ;
2015-07-25 03:29:45 +00:00
struct CRTFrameBuilder {
CRTFrame frame ;
2015-07-23 00:33:20 +00:00
2015-07-25 03:29:45 +00:00
CRTFrameBuilder ( int width , int height , int number_of_buffers , va_list buffer_sizes ) ;
~ CRTFrameBuilder ( ) ;
2015-07-23 00:33:20 +00:00
private :
2015-07-25 03:29:45 +00:00
std : : vector < uint16_t > _all_runs ;
2015-07-23 00:33:20 +00:00
void reset ( ) ;
void complete ( ) ;
2015-07-25 03:29:45 +00:00
uint16_t * get_next_run ( ) ;
2015-07-23 00:33:20 +00:00
friend CRT ;
void allocate_write_area ( int required_length ) ;
uint8_t * get_write_target_for_buffer ( int buffer ) ;
// a pointer to the section of content buffer currently being
// returned and to where the next section will begin
2015-07-27 03:50:43 +00:00
int _next_write_x_position , _next_write_y_position ;
2015-07-25 03:29:45 +00:00
int _write_x_position , _write_y_position ;
int _write_target_pointer ;
2015-07-23 00:33:20 +00:00
} ;
2015-07-31 21:47:10 +00:00
static const int kCRTNumberOfFrames = 4 ;
2015-07-23 00:33:20 +00:00
2015-07-19 17:36:27 +00:00
class CRT {
public :
2015-07-21 03:18:56 +00:00
CRT ( int cycles_per_line , int height_of_display , int number_of_buffers , . . . ) ;
2015-07-20 01:21:34 +00:00
~ CRT ( ) ;
2015-07-31 22:04:33 +00:00
void set_new_timing ( int cycles_per_line , int height_of_display ) ;
2015-07-19 17:36:27 +00:00
void output_sync ( int number_of_cycles ) ;
2015-07-21 03:18:56 +00:00
void output_blank ( int number_of_cycles ) ;
void output_level ( int number_of_cycles , const char * type ) ;
void output_data ( int number_of_cycles , const char * type ) ;
2015-07-19 22:32:42 +00:00
class CRTDelegate {
public :
2015-07-31 22:04:33 +00:00
virtual void crt_did_end_frame ( CRT * crt , CRTFrame * frame , bool did_detect_vsync ) = 0 ;
2015-07-19 22:32:42 +00:00
} ;
2015-07-22 22:15:18 +00:00
void set_delegate ( CRTDelegate * delegate ) ;
2015-07-23 00:33:20 +00:00
void return_frame ( ) ;
2015-07-19 22:32:42 +00:00
2015-07-20 01:21:34 +00:00
void allocate_write_area ( int required_length ) ;
uint8_t * get_write_target_for_buffer ( int buffer ) ;
2015-07-19 22:32:42 +00:00
private :
2015-07-25 03:36:44 +00:00
// the incoming clock lengths will be multiplied by something to give at least 1000
// sample points per line
int _time_multiplier ;
2015-07-21 20:37:39 +00:00
// fundamental creator-specified properties
int _cycles_per_line ;
int _height_of_display ;
// properties directly derived from there
int _hsync_error_window ; // the permitted window around the expected sync position in which a sync pulse will be recognised; calculated once at init
// the current scanning position
2015-07-22 22:15:18 +00:00
struct Vector {
2015-07-25 03:29:45 +00:00
uint32_t x , y ;
2015-08-02 23:30:45 +00:00
} _rasterPosition , _scanSpeed [ 4 ] , _beamWidth [ 4 ] ;
2015-07-27 03:50:43 +00:00
2015-07-23 00:33:20 +00:00
// the run delegate and the triple buffer
2015-07-25 03:29:45 +00:00
CRTFrameBuilder * _frame_builders [ kCRTNumberOfFrames ] ;
CRTFrameBuilder * _current_frame_builder ;
2015-07-23 00:33:20 +00:00
int _frames_with_delegate ;
int _frame_read_pointer ;
CRTDelegate * _delegate ;
2015-07-20 03:43:22 +00:00
2015-07-21 20:37:39 +00:00
// outer elements of sync separation
2015-07-22 22:15:18 +00:00
bool _is_receiving_sync ; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync)
bool _did_detect_hsync ; // true if horizontal sync was detected during this scanline (so, this affects flywheel adjustments)
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
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
2015-08-02 17:48:35 +00:00
int _is_in_vsync ;
2015-07-21 03:18:56 +00:00
2015-07-21 20:37:39 +00:00
// components of the flywheel sync
int _horizontal_counter ; // time run since the _start_ of the last horizontal sync
int _expected_next_hsync ; // our current expection of when the next horizontal sync will be encountered (which implies current flywheel velocity)
2015-07-22 22:15:18 +00:00
int _horizontal_retrace_time ;
2015-07-21 20:37:39 +00:00
bool _is_in_hsync ; // true for the duration of a horizontal sync — used to determine beam running direction and speed
2015-07-31 22:04:33 +00:00
bool _did_detect_vsync ; // true if vertical sync was detected in the input stream rather than forced by emergency measure
2015-07-21 20:37:39 +00:00
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
2015-07-25 03:29:45 +00:00
enum Type {
Sync , Level , Data , Blank
} type ;
2015-08-03 12:42:05 +00:00
void advance_cycles ( int number_of_cycles , bool hsync_requested , bool vsync_requested , bool vsync_charging , Type type , const char * data_type ) ;
2015-07-21 01:43:00 +00:00
2015-07-21 20:37:39 +00:00
// the inner entry point that determines whether and when the next sync event will occur within
// the current output window
2015-07-21 01:43:00 +00:00
enum SyncEvent {
None ,
StartHSync , EndHSync ,
StartVSync , EndVSync
} ;
2015-08-03 12:42:05 +00:00
SyncEvent get_next_vertical_sync_event ( bool vsync_is_requested , int cycles_to_run_for , int * cycles_advanced ) ;
2015-07-31 22:15:59 +00:00
SyncEvent get_next_horizontal_sync_event ( bool hsync_is_requested , int cycles_to_run_for , int * cycles_advanced ) ;
2015-07-19 17:36:27 +00:00
} ;
}
# endif /* CRT_cpp */