mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-27 06:35:04 +00:00
Added an attempt at NTSC/PAL autodetection, based on number of missed vertical syncs.
This commit is contained in:
parent
a5d66e9dd6
commit
9c91f1a2eb
@ -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] =
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user