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-08-16 20:08:29 +00:00
CRTFrameBuilder ( uint16_t width , uint16_t height , unsigned int number_of_buffers , va_list buffer_sizes ) ;
2015-07-25 03:29:45 +00:00
~ CRTFrameBuilder ( ) ;
2015-07-23 00:33:20 +00:00
private :
2015-08-06 01:12:33 +00:00
std : : vector < uint8_t > _all_runs ;
2015-07-23 00:33:20 +00:00
void reset ( ) ;
void complete ( ) ;
2015-08-06 01:12:33 +00:00
uint8_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-08-16 20:08:29 +00:00
uint16_t _next_write_x_position , _next_write_y_position ;
uint16_t _write_x_position , _write_y_position ;
2015-08-17 04:25:32 +00:00
size_t _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-08-16 20:08:29 +00:00
CRT ( unsigned int cycles_per_line , unsigned int height_of_display , unsigned int number_of_buffers , . . . ) ;
2015-07-20 01:21:34 +00:00
~ CRT ( ) ;
2015-08-16 20:08:29 +00:00
void set_new_timing ( unsigned int cycles_per_line , unsigned int height_of_display ) ;
2015-07-31 22:04:33 +00:00
2015-08-16 20:08:29 +00:00
void output_sync ( unsigned int number_of_cycles ) ;
void output_blank ( unsigned int number_of_cycles ) ;
void output_level ( unsigned int number_of_cycles , const char * type ) ;
void output_data ( unsigned 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
2015-08-16 20:08:29 +00:00
unsigned int _time_multiplier ;
2015-07-25 03:36:44 +00:00
2015-07-21 20:37:39 +00:00
// fundamental creator-specified properties
2015-08-16 20:08:29 +00:00
unsigned int _cycles_per_line ;
unsigned int _height_of_display ;
2015-07-21 20:37:39 +00:00
// properties directly derived from there
2015-08-16 20:08:29 +00:00
unsigned int _hsync_error_window ; // the permitted window around the expected sync position in which a sync pulse will be recognised; calculated once at init
2015-07-21 20:37:39 +00:00
// 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
2015-08-16 20:08:29 +00:00
unsigned int _horizontal_counter ; // time run since the _start_ of the last horizontal sync
unsigned int _expected_next_hsync ; // our current expection of when the next horizontal sync will be encountered (which implies current flywheel velocity)
unsigned 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-16 20:08:29 +00:00
void advance_cycles ( unsigned 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-16 20:08:29 +00:00
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 ) ;
2015-07-19 17:36:27 +00:00
} ;
}
# endif /* CRT_cpp */