mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-06 05:54:28 +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:
parent
51bcaea60c
commit
99a35266e1
@ -21,7 +21,9 @@ Machine::Machine() :
|
|||||||
rom_pages_{nullptr, nullptr, nullptr, nullptr},
|
rom_pages_{nullptr, nullptr, nullptr, nullptr},
|
||||||
tia_input_value_{0xff, 0xff},
|
tia_input_value_{0xff, 0xff},
|
||||||
cycles_since_speaker_update_(0),
|
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);
|
set_clock_rate(NTSC_clock_rate);
|
||||||
}
|
}
|
||||||
@ -31,6 +33,7 @@ void Machine::setup_output(float aspect_ratio)
|
|||||||
tia_.reset(new TIA);
|
tia_.reset(new TIA);
|
||||||
speaker_.reset(new Speaker);
|
speaker_.reset(new Speaker);
|
||||||
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
|
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
|
||||||
|
tia_->get_crt()->set_delegate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::close_output()
|
void Machine::close_output()
|
||||||
@ -288,3 +291,45 @@ void Machine::synchronise()
|
|||||||
update_video();
|
update_video();
|
||||||
speaker_->flush();
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -28,7 +28,8 @@ const unsigned int number_of_recorded_counters = 7;
|
|||||||
class Machine:
|
class Machine:
|
||||||
public CPU6502::Processor<Machine>,
|
public CPU6502::Processor<Machine>,
|
||||||
public CRTMachine::Machine,
|
public CRTMachine::Machine,
|
||||||
public ConfigurationTarget::Machine {
|
public ConfigurationTarget::Machine,
|
||||||
|
public Outputs::CRT::Delegate {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Machine();
|
Machine();
|
||||||
@ -51,6 +52,9 @@ class Machine:
|
|||||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return speaker_; }
|
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); }
|
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:
|
private:
|
||||||
uint8_t *rom_, *rom_pages_[4];
|
uint8_t *rom_, *rom_pages_[4];
|
||||||
size_t rom_size_;
|
size_t rom_size_;
|
||||||
@ -72,6 +76,17 @@ class Machine:
|
|||||||
// video backlog accumulation counter
|
// video backlog accumulation counter
|
||||||
unsigned int cycles_since_video_update_;
|
unsigned int cycles_since_video_update_;
|
||||||
void update_video();
|
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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode)
|
||||||
{
|
{
|
||||||
// this is the NTSC phase offset function; see below for PAL
|
Outputs::CRT::DisplayType display_type;
|
||||||
crt_->set_composite_sampling_function(
|
|
||||||
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
|
if(output_mode == OutputMode::NTSC)
|
||||||
"{"
|
{
|
||||||
"uint c = texture(texID, coordinate).r;"
|
crt_->set_composite_sampling_function(
|
||||||
"uint y = c & 14u;"
|
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
|
||||||
"uint iPhase = (c >> 4);"
|
"{"
|
||||||
|
"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));*/
|
/* 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";
|
// 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
|
// which will take 16*4 + 2 = 66 cycles from the first compare, implying the first compare must be
|
||||||
// in five cycles from now
|
// in five cycles from now
|
||||||
|
@ -11,42 +11,8 @@
|
|||||||
#include "Atari2600.hpp"
|
#include "Atari2600.hpp"
|
||||||
#import "CSMachine+Subclassing.h"
|
#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 {
|
@implementation CSAtari2600 {
|
||||||
Atari2600::Machine _atari2600;
|
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 {
|
- (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed {
|
||||||
@ -78,8 +44,6 @@ struct CRTDelegate: public Outputs::CRT::Delegate {
|
|||||||
- (void)setupOutputWithAspectRatio:(float)aspectRatio {
|
- (void)setupOutputWithAspectRatio:(float)aspectRatio {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
[super setupOutputWithAspectRatio:aspectRatio];
|
[super setupOutputWithAspectRatio:aspectRatio];
|
||||||
_atari2600.get_crt()->set_delegate(&_crtDelegate);
|
|
||||||
_crtDelegate.atari2600 = self;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user