1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-08 15:29:09 +00:00

Attempted to bring frequency-switching logic into the cross-platform realm. Which for now creates an issue with the OpenGL context.

This commit is contained in:
Thomas Harte 2017-02-19 21:20:37 -05:00
parent 51bcaea60c
commit 99a35266e1
4 changed files with 95 additions and 71 deletions

View File

@ -21,7 +21,9 @@ Machine::Machine() :
rom_pages_{nullptr, nullptr, nullptr, nullptr},
tia_input_value_{0xff, 0xff},
cycles_since_speaker_update_(0),
cycles_since_video_update_(0)
cycles_since_video_update_(0),
frame_record_pointer_(0),
is_ntsc_(true)
{
set_clock_rate(NTSC_clock_rate);
}
@ -31,6 +33,7 @@ void Machine::setup_output(float aspect_ratio)
tia_.reset(new TIA);
speaker_.reset(new Speaker);
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
tia_->get_crt()->set_delegate(this);
}
void Machine::close_output()
@ -288,3 +291,45 @@ void Machine::synchronise()
update_video();
speaker_->flush();
}
#pragma mark - CRT delegate
void Machine::crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs)
{
frame_records_[frame_record_pointer_].number_of_frames = number_of_frames;
frame_records_[frame_record_pointer_].number_of_unexpected_vertical_syncs = number_of_unexpected_vertical_syncs;
const size_t number_of_frame_records = sizeof(frame_records_) / sizeof(frame_records_[0]);
frame_record_pointer_ = (frame_record_pointer_ + 1) % number_of_frame_records;
unsigned int total_number_of_frames = 0;
unsigned int total_number_of_unexpected_vertical_syncs = 0;
for(size_t c = 0; c < number_of_frame_records; c++)
{
if(!frame_records_[c].number_of_frames) return;
total_number_of_frames += frame_records_[c].number_of_frames;
total_number_of_unexpected_vertical_syncs += frame_records_[c].number_of_unexpected_vertical_syncs;
}
if(total_number_of_unexpected_vertical_syncs >= total_number_of_frames >> 1)
{
for(size_t c = 0; c < number_of_frame_records; c++)
{
frame_records_[c].number_of_frames = 0;
frame_records_[c].number_of_unexpected_vertical_syncs = 0;
}
is_ntsc_ ^= true;
if(is_ntsc_)
{
set_clock_rate(NTSC_clock_rate);
tia_->set_output_mode(TIA::OutputMode::NTSC);
}
else
{
set_clock_rate(PAL_clock_rate);
tia_->set_output_mode(TIA::OutputMode::PAL);
}
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
}
}

View File

@ -28,7 +28,8 @@ const unsigned int number_of_recorded_counters = 7;
class Machine:
public CPU6502::Processor<Machine>,
public CRTMachine::Machine,
public ConfigurationTarget::Machine {
public ConfigurationTarget::Machine,
public Outputs::CRT::Delegate {
public:
Machine();
@ -51,6 +52,9 @@ class Machine:
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return speaker_; }
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
// to satisfy Outputs::CRT::Delegate
virtual void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs);
private:
uint8_t *rom_, *rom_pages_[4];
size_t rom_size_;
@ -72,6 +76,17 @@ class Machine:
// video backlog accumulation counter
unsigned int cycles_since_video_update_;
void update_video();
// output frame rate tracker
struct FrameRecord
{
unsigned int number_of_frames;
unsigned int number_of_unexpected_vertical_syncs;
FrameRecord() : number_of_frames(0), number_of_unexpected_vertical_syncs(0) {}
} frame_records_[4];
unsigned int frame_record_pointer_;
bool is_ntsc_;
};
}

View File

@ -143,17 +143,40 @@ TIA::TIA(std::function<void(uint8_t *output_buffer)> line_end_function) : TIA(fa
void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode)
{
// this is the NTSC phase offset function; see below for PAL
crt_->set_composite_sampling_function(
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
"{"
"uint c = texture(texID, coordinate).r;"
"uint y = c & 14u;"
"uint iPhase = (c >> 4);"
Outputs::CRT::DisplayType display_type;
if(output_mode == OutputMode::NTSC)
{
crt_->set_composite_sampling_function(
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
"{"
"uint c = texture(texID, coordinate).r;"
"uint y = c & 14u;"
"uint iPhase = (c >> 4);"
"float phaseOffset = 6.283185308 * float(iPhase) / 13.0 + 5.074880441076923;"
"return mix(float(y) / 14.0, step(1, iPhase) * cos(phase + phaseOffset), amplitude);"
"}");
display_type = Outputs::CRT::DisplayType::NTSC60;
}
else
{
crt_->set_composite_sampling_function(
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
"{"
"uint c = texture(texID, coordinate).r;"
"uint y = c & 14u;"
"uint iPhase = (c >> 4);"
"uint direction = iPhase & 1u;"
"float phaseOffset = float(7u - direction) + (float(direction) - 0.5) * 2.0 * float(iPhase >> 1);"
"phaseOffset *= 6.283185308 / 12.0;"
"return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);"
"}");
display_type = Outputs::CRT::DisplayType::PAL50;
}
crt_->set_new_display_type(cycles_per_line * 2 + 1, display_type);
"float phaseOffset = 6.283185308 * float(iPhase) / 13.0 + 5.074880441076923;"
"return mix(float(y) / 14.0, step(1, iPhase) * cos(phase + phaseOffset), amplitude);"
"}");
/* speaker_->set_input_rate((float)(get_clock_rate() / 38.0));*/
}
@ -161,29 +184,6 @@ TIA::~TIA()
{
}
/*void Machine::switch_region()
{
// the PAL function
crt_->set_composite_sampling_function(
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
"{"
"uint c = texture(texID, coordinate).r;"
"uint y = c & 14u;"
"uint iPhase = (c >> 4);"
"uint direction = iPhase & 1u;"
"float phaseOffset = float(7u - direction) + (float(direction) - 0.5) * 2.0 * float(iPhase >> 1);"
"phaseOffset *= 6.283185308 / 12.0;"
"return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);"
"}");
crt_->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1, true);
is_pal_region_ = true;
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
set_clock_rate(PAL_clock_rate);
}*/
// justification for +5: "we need to wait at least 71 [clocks] before the HMOVE operation is complete";
// which will take 16*4 + 2 = 66 cycles from the first compare, implying the first compare must be
// in five cycles from now

View File

@ -11,42 +11,8 @@
#include "Atari2600.hpp"
#import "CSMachine+Subclassing.h"
@interface CSAtari2600 ()
- (void)crt:(Outputs::CRT::CRT *)crt didEndBatchOfFrames:(unsigned int)numberOfFrames withUnexpectedVerticalSyncs:(unsigned int)numberOfUnexpectedSyncs;
@end
struct CRTDelegate: public Outputs::CRT::Delegate {
__weak CSAtari2600 *atari2600;
void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) {
[atari2600 crt:crt didEndBatchOfFrames:number_of_frames withUnexpectedVerticalSyncs:number_of_unexpected_vertical_syncs];
}
};
@implementation CSAtari2600 {
Atari2600::Machine _atari2600;
CRTDelegate _crtDelegate;
int _frameCount;
int _hitCount;
BOOL _didDecideRegion;
int _batchesReceived;
}
- (void)crt:(Outputs::CRT::CRT *)crt didEndBatchOfFrames:(unsigned int)numberOfFrames withUnexpectedVerticalSyncs:(unsigned int)numberOfUnexpectedSyncs {
if(!_didDecideRegion)
{
_batchesReceived++;
if(_batchesReceived == 2)
{
_didDecideRegion = YES;
if(numberOfUnexpectedSyncs >= numberOfFrames >> 1)
{
[self.view performWithGLContext:^{
// _atari2600.switch_region();
}];
}
}
}
}
- (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed {
@ -78,8 +44,6 @@ struct CRTDelegate: public Outputs::CRT::Delegate {
- (void)setupOutputWithAspectRatio:(float)aspectRatio {
@synchronized(self) {
[super setupOutputWithAspectRatio:aspectRatio];
_atari2600.get_crt()->set_delegate(&_crtDelegate);
_crtDelegate.atari2600 = self;
}
}