1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Added an attempt at NTSC/PAL autodetection, based on number of missed vertical syncs.

This commit is contained in:
Thomas Harte 2015-07-31 18:04:33 -04:00
parent a5d66e9dd6
commit 9c91f1a2eb
6 changed files with 43 additions and 8 deletions

View File

@ -20,7 +20,7 @@ Machine::Machine()
_horizontalTimer = horizontalTimerReload;
_lastOutputStateDuration = 0;
_lastOutputState = OutputState::Sync;
_crt = new Outputs::CRT(228, 312, 1, 4);
_crt = new Outputs::CRT(228, 262, 1, 4);
_piaTimerStatus = 0xff;
setup6502();
@ -31,6 +31,12 @@ Machine::~Machine()
delete _crt;
}
void Machine::switch_region()
{
_crt->set_new_timing(228, 312);
}
void Machine::get_output_pixel(uint8_t *pixel, int offset)
{
const uint8_t palette[16][3] =

View File

@ -25,6 +25,7 @@ class Machine: public CPU6502::Processor<Machine> {
int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
void set_rom(size_t length, const uint8_t *data);
void switch_region();
Outputs::CRT *get_crt() { return _crt; }

View File

@ -10,12 +10,12 @@
#import "Atari2600.hpp"
@interface CSAtari2600 (Callbacks)
- (void)crtDidEndFrame:(CRTFrame *)frame;
- (void)crtDidEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync;
@end
struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate {
__weak CSAtari2600 *atari;
void crt_did_end_frame(Outputs::CRT *crt, CRTFrame *frame) { [atari crtDidEndFrame:frame]; }
void crt_did_end_frame(Outputs::CRT *crt, CRTFrame *frame, bool did_detect_vsync) { [atari crtDidEndFrame:frame didDetectVSync:did_detect_vsync]; }
};
@implementation CSAtari2600 {
@ -23,9 +23,25 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate {
Atari2600CRTDelegate _crtDelegate;
dispatch_queue_t _serialDispatchQueue;
int _failedVSyncCount;
}
- (void)crtDidEndFrame:(CRTFrame *)frame {
- (void)crtDidEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync {
if(!didDetectVSync)
{
_failedVSyncCount++;
if(_failedVSyncCount == 60)
{
_atari2600.switch_region();
}
}
else
{
_failedVSyncCount = MAX(_failedVSyncCount - 2, 0);
}
dispatch_async(dispatch_get_main_queue(), ^{
BOOL hasReturn = [self.view pushFrame:frame];

View File

@ -121,6 +121,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
- (BOOL)pushFrame:(CRTFrame * __nonnull)crtFrame
{
BOOL hadFrame = _crtFrame ? YES : NO;
_crtFrame = crtFrame;
[self setNeedsDisplay:YES];
@ -140,7 +141,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _crtFrame->size.width, _crtFrame->dirty_size.height, GL_RGBA, GL_UNSIGNED_BYTE, _crtFrame->buffers[0].data);
}
return YES;
return hadFrame;
}
#pragma mark - Frame output

View File

@ -18,7 +18,7 @@ static const uint32_t kCRTFixedPointOffset = 0x08000000;
#define kRetraceXMask 0x01
#define kRetraceYMask 0x02
CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
void CRT::set_new_timing(int cycles_per_line, int height_of_display)
{
const int syncCapacityLineChargeThreshold = 5;
const int millisecondsHorizontalRetraceTime = 7; // source: Dictionary of Video and Television Technology, p. 234
@ -61,6 +61,11 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
float halfLineWidth = (float)_height_of_display * 1.6f;
_widths[0][0] = (sinf(angle) / halfLineWidth) * kCRTFixedPointRange;
_widths[0][1] = (cosf(angle) / halfLineWidth) * kCRTFixedPointRange;
}
CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...)
{
set_new_timing(cycles_per_line, height_of_display);
// generate buffers for signal storage as requested — format is
// number of buffers, size of buffer 1, size of buffer 2...
@ -122,6 +127,7 @@ CRT::SyncEvent CRT::next_vertical_sync_event(bool vsync_is_charging, int cycles_
if(proposed_sync_y > (kCRTFixedPointRange * 15) >> 4) {
proposedSyncTime = _sync_capacitor_charge_threshold - _sync_capacitor_charge_level;
proposedEvent = SyncEvent::StartVSync;
_did_detect_vsync = true;
}
}
}
@ -298,7 +304,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
{
_current_frame_builder->complete();
_frames_with_delegate++;
_delegate->crt_did_end_frame(this, &_current_frame_builder->frame);
_delegate->crt_did_end_frame(this, &_current_frame_builder->frame, _did_detect_hsync);
}
if(_frames_with_delegate < kCRTNumberOfFrames)
@ -309,6 +315,8 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
}
else
_current_frame_builder = nullptr;
_did_detect_vsync = false;
break;
default: break;

View File

@ -51,6 +51,8 @@ class CRT {
CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...);
~CRT();
void set_new_timing(int cycles_per_line, int height_of_display);
void output_sync(int number_of_cycles);
void output_blank(int number_of_cycles);
void output_level(int number_of_cycles, const char *type);
@ -58,7 +60,7 @@ class CRT {
class CRTDelegate {
public:
virtual void crt_did_end_frame(CRT *crt, CRTFrame *frame) = 0;
virtual void crt_did_end_frame(CRT *crt, CRTFrame *frame, bool did_detect_vsync) = 0;
};
void set_delegate(CRTDelegate *delegate);
void return_frame();
@ -105,6 +107,7 @@ class CRT {
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
bool _did_detect_vsync; // true if vertical sync was detected in the input stream rather than forced by emergency measure
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
enum Type {