1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-17 21:30:14 +00:00

Made a quick attempt to accumulate a list of detected output runs. Which means finally having to specify normal frame height. I'm already at too many magic formulae though, so this will need proper revision when I'm next awake. Definitely my horizontal position advancement is way off.

This commit is contained in:
Thomas Harte 2015-07-20 23:18:56 -04:00
parent 4fa315ab4d
commit a1a1b15d18
3 changed files with 114 additions and 47 deletions

View File

@ -11,6 +11,7 @@
#include <stdio.h>
using namespace Atari2600;
static const char atari2600DataType[] = "Atari2600";
Machine::Machine()
{
@ -18,7 +19,7 @@ Machine::Machine()
_horizontalTimer = 0;
_lastOutputStateDuration = 0;
_lastOutputState = OutputState::Sync;
_crt = new Outputs::CRT(228, 1, 4);
_crt = new Outputs::CRT(228, 256, 1, 4);
reset();
}
@ -84,10 +85,10 @@ void Machine::output_state(OutputState state, uint8_t *pixel)
_outputBuffer = _crt->get_write_target_for_buffer(0);
_outputBuffer[0] = _outputBuffer[1] = _outputBuffer[2] = 0;
_outputBuffer[3] = 0xff;
_crt->output_level(_lastOutputStateDuration, "Atari2600");
_crt->output_level(_lastOutputStateDuration, atari2600DataType);
} break;
case OutputState::Sync: _crt->output_sync(_lastOutputStateDuration); break;
case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, "Atari2600"); break;
case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, atari2600DataType); break;
}
_lastOutputStateDuration = 0;
_lastOutputState = state;

View File

@ -20,8 +20,11 @@ static const int scanlinesVerticalRetraceTime = 26;
using namespace Outputs;
CRT::CRT(int cycles_per_line, int number_of_buffers, ...)
CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
{
_height_of_display = height_of_display;
_cycles_per_line = cycles_per_line;
_horizontalOffset = 0.0f;
_verticalOffset = 0.0f;
@ -39,13 +42,15 @@ CRT::CRT(int cycles_per_line, int number_of_buffers, ...)
va_end(va);
_write_allocation_pointer = 0;
_cycles_per_line = cycles_per_line;
_expected_next_hsync = cycles_per_line;
_hsync_error_window = cycles_per_line >> 5;
_horizontal_counter = 0;
_sync_capacitor_charge_level = 0;
_is_in_sync = false;
_is_receiving_sync = false;
_is_in_hsync = false;
_run_pointer = 0;
}
CRT::~CRT()
@ -74,6 +79,12 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
SyncEvent proposedEvent = SyncEvent::None;
int proposedSyncTime = cycles_to_run_for;
// have we overrun the maximum permitted number of horizontal syncs for this frame?
if (_hsync_counter > _height_of_display + 10) {
*cycles_advanced = 0;
return SyncEvent::StartHSync;
}
// will we end an ongoing hsync?
const int endOfHSyncTime = (millisecondsHorizontalRetraceTime*_cycles_per_line) >> 6;
if (_horizontal_counter < endOfHSyncTime && _horizontal_counter+proposedSyncTime >= endOfHSyncTime) {
@ -97,8 +108,6 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
}
}
// TODO: will a late-in-the-day vertical sync be forced?
// will an ongoing vertical sync end?
if (_vretrace_counter > 0) {
if (_vretrace_counter < proposedSyncTime) {
@ -111,23 +120,62 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
return proposedEvent;
}
void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool vsync_charging, const CRTRun::Type type)
void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool vsync_charging, const CRTRun::Type type, const char *data_type)
{
int buffer_offset = 0;
while(number_of_cycles) {
int next_run_length;
SyncEvent next_event = advance_to_next_sync_event(hsync_requested, vsync_charging, number_of_cycles, &next_run_length);
for(int c = 0; c < next_run_length; c++)
if(_run_pointer >= _all_runs.size())
{
switch(type)
{
case CRTRun::Type::Data: putc('-', stdout); break;
case CRTRun::Type::Blank: putc(' ', stdout); break;
case CRTRun::Type::Level: putc('_', stdout); break;
case CRTRun::Type::Sync: putc('<', stdout); break;
}
_all_runs.resize((_all_runs.size() * 2)+1);
}
CRTRun *nextRun = &_all_runs[_run_pointer];
_run_pointer++;
nextRun->type = type;
nextRun->start_point.dst_x = _horizontalOffset;
nextRun->start_point.dst_y = _verticalOffset;
if(type == CRTRun::Type::Data || type == CRTRun::Type::Level)
{
nextRun->start_point.src_x = (_write_target_pointer + buffer_offset) & (bufferWidth - 1);
nextRun->start_point.dst_x = (_write_target_pointer + buffer_offset) / bufferWidth;
}
nextRun->data_type = data_type;
if (_vretrace_counter > 0)
{
_verticalOffset = std::max(0.0f, _verticalOffset - (float)number_of_cycles / (float)(scanlinesVerticalRetraceTime * _cycles_per_line));
}
else
{
_verticalOffset = std::min(1.0f, _verticalOffset + (float)number_of_cycles / (float)(_height_of_display * _cycles_per_line));
}
if (_is_in_hsync)
{
_horizontalOffset = std::max(0.0f, _horizontalOffset - (float)(((millisecondsHorizontalRetraceTime * _cycles_per_line) >> 6) * number_of_cycles) / (float)_cycles_per_line);
}
else
{
_horizontalOffset = std::min(1.0f, _horizontalOffset + (float)((((64 - millisecondsHorizontalRetraceTime) * _cycles_per_line) >> 6) * number_of_cycles) / (float)_cycles_per_line);
}
nextRun->end_point.dst_x = _horizontalOffset;
nextRun->end_point.dst_y = _verticalOffset;
if(type == CRTRun::Type::Data)
{
buffer_offset += next_run_length;
}
if(type == CRTRun::Type::Data || type == CRTRun::Type::Level)
{
nextRun->end_point.src_x = (_write_target_pointer + buffer_offset) & (bufferWidth - 1);
nextRun->end_point.dst_x = (_write_target_pointer + buffer_offset) / bufferWidth;
}
// printf("[[%d]%d:%d]", type, next_event, next_run_length);
hsync_requested = false;
@ -144,48 +192,62 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
default: break;
case SyncEvent::StartHSync:
_horizontal_counter = 0;
printf("\n");
_is_in_hsync = true;
_hsync_counter++;
break;
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;
case SyncEvent::StartVSync:
_vretrace_counter = scanlinesVerticalRetraceTime * _cycles_per_line;
printf("\n\n===\n\n");
_hsync_counter = 0;
break;
case SyncEvent::EndVSync:
if(_delegate != nullptr)
_delegate->crt_did_start_vertical_retrace_with_runs(&_all_runs[0], _run_pointer);
_run_pointer = 0;
break;
}
}
}
#pragma mark - delegate
void CRT::set_crt_delegate(CRTDelegate *delegate)
{
_delegate = delegate;
}
#pragma mark - stream feeding methods
void CRT::output_sync(int number_of_cycles)
{
bool _hsync_requested = !_is_in_sync;
_is_in_sync = true;
advance_cycles(number_of_cycles, _hsync_requested, true, CRTRun::Type::Sync);
bool _hsync_requested = !_is_receiving_sync;
_is_receiving_sync = true;
advance_cycles(number_of_cycles, _hsync_requested, true, CRTRun::Type::Sync, nullptr);
}
void CRT::output_level(int number_of_cycles, std::string type)
void CRT::output_blank(int number_of_cycles)
{
_is_in_sync = false;
advance_cycles(number_of_cycles, false, false, CRTRun::Type::Level);
_is_receiving_sync = false;
advance_cycles(number_of_cycles, false, false, CRTRun::Type::Blank, nullptr);
}
void CRT::output_data(int number_of_cycles, std::string type)
void CRT::output_level(int number_of_cycles, const char *type)
{
_is_in_sync = false;
advance_cycles(number_of_cycles, false, false, CRTRun::Type::Data);
_is_receiving_sync = false;
advance_cycles(number_of_cycles, false, false, CRTRun::Type::Level, type);
}
void CRT::output_blank(int number_of_cycles, std::string type)
void CRT::output_data(int number_of_cycles, const char *type)
{
_is_in_sync = false;
advance_cycles(number_of_cycles, false, false, CRTRun::Type::Blank);
_is_receiving_sync = false;
advance_cycles(number_of_cycles, false, false, CRTRun::Type::Data, type);
}
#pragma mark - Buffer supply

View File

@ -11,44 +11,46 @@
#include <stdint.h>
#include <string>
#include <forward_list>
#include <vector>
namespace Outputs {
class CRT {
public:
CRT(int cycles_per_line, int number_of_buffers, ...);
CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...);
~CRT();
void output_sync(int number_of_cycles);
void output_level(int number_of_cycles, std::string type);
void output_blank(int number_of_cycles, std::string type);
void output_data(int number_of_cycles, std::string type);
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);
struct CRTRun {
struct Point {
float x, y;
float dst_x, dst_y;
int src_x, src_y;
} start_point, end_point;
enum Type {
Sync, Level, Data, Blank
} type;
std::string data_type;
uint8_t *data;
const char *data_type;
};
class CRTDelegate {
public:
void crt_did_start_vertical_retrace_with_runs(std::forward_list<CRTRun> *runs, int runs_to_draw);
virtual void crt_did_start_vertical_retrace_with_runs(CRTRun *runs, int runs_to_draw) = 0;
};
void set_crt_delegate(CRTDelegate *);
void set_crt_delegate(CRTDelegate *delegate);
void allocate_write_area(int required_length);
uint8_t *get_write_target_for_buffer(int buffer);
private:
CRTDelegate *_delegate;
std::vector<CRTRun> _all_runs;
int _run_pointer;
float _horizontalOffset, _verticalOffset;
@ -58,8 +60,6 @@ class CRT {
int _write_allocation_pointer, _write_target_pointer;
std::forward_list<CRTRun> _runs;
void propose_hsync();
void charge_vsync(int number_of_cycles);
void drain_vsync(int number_of_cycles);
@ -69,6 +69,9 @@ class CRT {
void do_vsync();
int _cycles_per_line;
int _height_of_display;
int _hsync_counter;
enum SyncEvent {
None,
@ -76,11 +79,12 @@ class CRT {
StartVSync, EndVSync
};
SyncEvent advance_to_next_sync_event(bool hsync_is_requested, bool vsync_is_charging, int cycles_to_run_for, int *cycles_advanced);
bool _is_in_sync, _did_detect_hsync;
bool _is_receiving_sync, _did_detect_hsync;
int _sync_capacitor_charge_level, _vretrace_counter;
int _horizontal_counter, _expected_next_hsync, _hsync_error_window;
bool _is_in_hsync;
void advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_charging, CRTRun::Type type);
void advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_charging, CRTRun::Type type, const char *data_type);
};
}