1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-05 19:37:19 +00:00

Attempted to switch to slightly more meaningful names within the CRT and implemented a delegate to investigate output. Working on it.

This commit is contained in:
Thomas Harte 2015-07-22 18:15:18 -04:00
parent 908c171d2d
commit 963cb2f6fb
5 changed files with 101 additions and 55 deletions

View File

@ -24,6 +24,8 @@ class Machine: public CPU6502::Processor<Machine> {
void set_rom(size_t length, const uint8_t *data);
Outputs::CRT *get_crt() { return _crt; }
private:
uint8_t _rom[4096], _ram[128];
uint16_t _romMask;

View File

@ -9,8 +9,42 @@
#import "Atari2600.h"
#import "Atari2600.hpp"
class Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate {
void crt_did_start_vertical_retrace_with_runs(Outputs::CRT::CRTRun *runs, int runs_to_draw)
{
printf("===\n\n");
for(int run = 0; run < runs_to_draw; run++)
{
char character = ' ';
switch(runs[run].type)
{
case Outputs::CRT::CRTRun::Type::Sync: character = '<'; break;
case Outputs::CRT::CRTRun::Type::Level: character = '_'; break;
case Outputs::CRT::CRTRun::Type::Data: character = '-'; break;
case Outputs::CRT::CRTRun::Type::Blank: character = ' '; break;
}
// if(runs[run].start_point.dst_x > runs[run].end_point.dst_x)
// {
// printf("\n");
// }
float length = fabsf(runs[run].end_point.dst_x - runs[run].start_point.dst_x);
int iLength = (int)(length * 64.0);
for(int c = 0; c < iLength; c++)
{
putc(character, stdout);
}
if (runs[run].type == Outputs::CRT::CRTRun::Type::Sync) printf("\n");
}
}
};
@implementation CSAtari2600 {
Atari2600::Machine _atari2600;
Atari2600CRTDelegate _crtDelegate;
}
- (void)runForNumberOfCycles:(int)cycles {
@ -21,4 +55,14 @@
_atari2600.set_rom(rom.length, (const uint8_t *)rom.bytes);
}
- (instancetype)init {
self = [super init];
if (self) {
_atari2600.get_crt()->set_delegate(&_crtDelegate);
}
return self;
}
@end

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8152.3" systemVersion="14E46" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8164.2" systemVersion="14E46" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8152.3"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8164.2"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="Atari2600Document" customModule="Clock_Signal" customModuleProvider="target">
@ -12,7 +12,7 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="133" y="235" width="507" height="413"/>

View File

@ -12,14 +12,14 @@
static const int bufferWidth = 512;
static const int bufferHeight = 512;
static const int syncCapacityLineChargeThreshold = 3;
static const int millisecondsHorizontalRetraceTime = 16;
static const int scanlinesVerticalRetraceTime = 26;
using namespace Outputs;
CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
{
static const int syncCapacityLineChargeThreshold = 3;
static const int millisecondsHorizontalRetraceTime = 16;
static const int scanlinesVerticalRetraceTime = 26;
// store fundamental display configuration properties
_height_of_display = height_of_display;
_cycles_per_line = cycles_per_line;
@ -27,6 +27,15 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
// generate timing values implied by the given arbuments
_hsync_error_window = cycles_per_line >> 5;
_sync_capacitor_charge_threshold = syncCapacityLineChargeThreshold * cycles_per_line;
_horizontal_retrace_time = (millisecondsHorizontalRetraceTime * cycles_per_line) >> 6;
_vertical_retrace_time = scanlinesVerticalRetraceTime * cycles_per_line;
_scanSpeed.x = 1.0f / (float)cycles_per_line;
_scanSpeed.y = 1.0f / (float)height_of_display;
_retraceSpeed.x = 1.0f / (float)_horizontal_retrace_time;
_retraceSpeed.y = 1.0f / (float)_vertical_retrace_time;
// generate buffers for signal storage as requested — format is
// number of buffers, size of buffer 1, size of buffer 2...
_numberOfBuffers = number_of_buffers;
@ -49,8 +58,7 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
_run_pointer = 0;
// reset raster position
_horizontalOffset = 0.0f;
_verticalOffset = 0.0f;
_rasterPosition.x = _rasterPosition.y = 0.0f;
// reset flywheel sync
_expected_next_hsync = cycles_per_line;
@ -62,6 +70,7 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
// start off not in horizontal sync, not receiving a sync signal
_is_receiving_sync = false;
_is_in_hsync = false;
_vretrace_counter = 0;
}
CRT::~CRT()
@ -91,15 +100,18 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
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;
if (!_vretrace_counter)
{
float raster_distance = _scanSpeed.y * (float)proposedSyncTime;
if(_rasterPosition.y < 1.02f && _rasterPosition.y + raster_distance >= 1.02f) {
proposedSyncTime = (int)(1.02f - _rasterPosition.y) / _scanSpeed.y;
proposedEvent = SyncEvent::StartVSync;
}
}
// will we end an ongoing hsync?
const int endOfHSyncTime = (millisecondsHorizontalRetraceTime*_cycles_per_line) >> 6;
if (_horizontal_counter < endOfHSyncTime && _horizontal_counter+proposedSyncTime >= endOfHSyncTime) {
proposedSyncTime = endOfHSyncTime - _horizontal_counter;
if (_horizontal_counter < _horizontal_retrace_time && _horizontal_counter+proposedSyncTime >= _horizontal_retrace_time) {
proposedSyncTime = _horizontal_retrace_time - _horizontal_counter;
proposedEvent = SyncEvent::EndHSync;
}
@ -111,10 +123,8 @@ CRT::SyncEvent CRT::advance_to_next_sync_event(bool hsync_is_requested, bool vsy
// will an acceptable vertical sync be triggered?
if (vsync_is_charging && !_vretrace_counter) {
const int startOfVSyncTime = syncCapacityLineChargeThreshold*_cycles_per_line;
if (_sync_capacitor_charge_level < startOfVSyncTime && _sync_capacitor_charge_level + proposedSyncTime >= startOfVSyncTime) {
proposedSyncTime = startOfVSyncTime - _sync_capacitor_charge_level;
if (_sync_capacitor_charge_level < _sync_capacitor_charge_threshold && _sync_capacitor_charge_level + proposedSyncTime >= _sync_capacitor_charge_threshold) {
proposedSyncTime = _sync_capacitor_charge_threshold - _sync_capacitor_charge_level;
proposedEvent = SyncEvent::StartVSync;
}
}
@ -155,39 +165,31 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
// set the type, initial raster position and type of this run
nextRun->type = type;
nextRun->start_point.dst_x = _horizontalOffset;
nextRun->start_point.dst_y = _verticalOffset;
nextRun->start_point.dst_x = _rasterPosition.x;
nextRun->start_point.dst_y = _rasterPosition.y;
nextRun->data_type = data_type;
// if this is a data or level run then store a starting data position
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->start_point.src_y = (_write_target_pointer + buffer_offset) / bufferWidth;
}
// advance the raster position as dictated by current sync status
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);
}
_rasterPosition.x = std::max(0.0f, _rasterPosition.x - (float)number_of_cycles * _retraceSpeed.x);
else
{
_horizontalOffset = std::min(1.0f, _horizontalOffset + (float)((((64 - millisecondsHorizontalRetraceTime) * _cycles_per_line) >> 6) * number_of_cycles) / (float)_cycles_per_line);
}
_rasterPosition.x = std::min(1.0f, _rasterPosition.x + (float)number_of_cycles * _scanSpeed.x);
if (_vretrace_counter > 0)
_rasterPosition.y = std::max(0.0f, _rasterPosition.y - (float)number_of_cycles * _retraceSpeed.y);
else
_rasterPosition.y = std::min(1.0f, _rasterPosition.y + (float)number_of_cycles * _scanSpeed.y);
// store the final raster position
nextRun->end_point.dst_x = _horizontalOffset;
nextRun->end_point.dst_y = _verticalOffset;
nextRun->end_point.dst_x = _rasterPosition.x;
nextRun->end_point.dst_y = _rasterPosition.y;
// if this is a data run then advance the buffer pointer
if(type == CRTRun::Type::Data)
@ -199,7 +201,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
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;
nextRun->end_point.src_y = (_write_target_pointer + buffer_offset) / bufferWidth;
}
// decrement the number of cycles left to run for and increment the
@ -224,7 +226,6 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
case SyncEvent::StartHSync:
_horizontal_counter = 0;
_is_in_hsync = true;
_hsync_counter++;
break;
// end of horizontal sync: update the flywheel's velocity, note that we're no longer
@ -240,8 +241,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
// start of vertical sync: reset the lines-in-this-frame counter,
// load the retrace counter with the amount of time it'll take to retrace
case SyncEvent::StartVSync:
_vretrace_counter = scanlinesVerticalRetraceTime * _cycles_per_line;
_hsync_counter = 0;
_vretrace_counter = _vertical_retrace_time;
break;
// end of vertical sync: tell the delegate that we finished vertical sync,
@ -259,7 +259,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
#pragma mark - delegate
void CRT::set_crt_delegate(CRTDelegate *delegate)
void CRT::set_delegate(CRTDelegate *delegate)
{
_delegate = delegate;
}

View File

@ -42,7 +42,7 @@ class CRT {
public:
virtual void crt_did_start_vertical_retrace_with_runs(CRTRun *runs, int runs_to_draw) = 0;
};
void set_crt_delegate(CRTDelegate *delegate);
void set_delegate(CRTDelegate *delegate);
void allocate_write_area(int required_length);
uint8_t *get_write_target_for_buffer(int buffer);
@ -61,7 +61,9 @@ class CRT {
int _run_pointer;
// the current scanning position
float _horizontalOffset, _verticalOffset;
struct Vector {
float x, y;
} _rasterPosition, _scanSpeed, _retraceSpeed;
// the content buffers
uint8_t **_buffers;
@ -72,20 +74,18 @@ class CRT {
// returned and to where the next section will begin
int _write_allocation_pointer, _write_target_pointer;
// a counter of horizontal syncs, to allow an automatic vertical
// sync to be triggered if we appear to be exiting the display
// (TODO: switch to evaluating _verticalOffset for this)
int _hsync_counter;
// outer elements of sync separation
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 _vretrace_counter; // a down-counter for time during a vertical retrace
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
int _vretrace_counter; // a down-counter for time during a vertical retrace
int _vertical_retrace_time;
// 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)
int _horizontal_retrace_time;
bool _is_in_hsync; // true for the duration of a horizontal sync — used to determine beam running direction and speed
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data