mirror of
https://github.com/TomHarte/CLK.git
synced 2024-08-27 13:29:12 +00:00
Merge pull request #202 from TomHarte/AtariInline
Catches the Atari 2600 up with the no-internals-published trend.
This commit is contained in:
commit
f1e64169cd
@ -45,7 +45,7 @@ enum Key: uint16_t {
|
||||
};
|
||||
|
||||
/*!
|
||||
Models an Amstrad CPC, a CRT-outputting machine with a keyboard that can accept configuration targets.
|
||||
Models an Amstrad CPC.
|
||||
*/
|
||||
class Machine:
|
||||
public CRTMachine::Machine,
|
||||
@ -54,7 +54,7 @@ class Machine:
|
||||
public:
|
||||
virtual ~Machine();
|
||||
|
||||
/// Creates an returns an Amstrad CPC on the heap.
|
||||
/// Creates and returns an Amstrad CPC on the heap.
|
||||
static Machine *AmstradCPC();
|
||||
|
||||
/// Sets the contents of rom @c type to @c data. Assumed to be a setup step; has no effect once a machine is running.
|
||||
|
@ -23,64 +23,28 @@
|
||||
#include "Cartridges/Tigervision.hpp"
|
||||
#include "Cartridges/Unpaged.hpp"
|
||||
|
||||
using namespace Atari2600;
|
||||
namespace {
|
||||
static const double NTSC_clock_rate = 1194720;
|
||||
static const double PAL_clock_rate = 1182298;
|
||||
}
|
||||
|
||||
Machine::Machine() :
|
||||
namespace Atari2600 {
|
||||
|
||||
class ConcreteMachine:
|
||||
public Machine,
|
||||
public Outputs::CRT::Delegate {
|
||||
public:
|
||||
ConcreteMachine() :
|
||||
frame_record_pointer_(0),
|
||||
is_ntsc_(true) {
|
||||
set_clock_rate(NTSC_clock_rate);
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::setup_output(float aspect_ratio) {
|
||||
bus_->tia_.reset(new TIA);
|
||||
bus_->speaker_.reset(new Speaker);
|
||||
bus_->speaker_->set_input_rate((float)(get_clock_rate() / (double)CPUTicksPerAudioTick));
|
||||
bus_->tia_->get_crt()->set_delegate(this);
|
||||
}
|
||||
|
||||
void Machine::close_output() {
|
||||
bus_.reset();
|
||||
}
|
||||
|
||||
Machine::~Machine() {
|
||||
~ConcreteMachine() {
|
||||
close_output();
|
||||
}
|
||||
|
||||
void Machine::set_digital_input(Atari2600DigitalInput input, bool state) {
|
||||
switch (input) {
|
||||
case Atari2600DigitalInputJoy1Up: bus_->mos6532_.update_port_input(0, 0x10, state); break;
|
||||
case Atari2600DigitalInputJoy1Down: bus_->mos6532_.update_port_input(0, 0x20, state); break;
|
||||
case Atari2600DigitalInputJoy1Left: bus_->mos6532_.update_port_input(0, 0x40, state); break;
|
||||
case Atari2600DigitalInputJoy1Right: bus_->mos6532_.update_port_input(0, 0x80, state); break;
|
||||
|
||||
case Atari2600DigitalInputJoy2Up: bus_->mos6532_.update_port_input(0, 0x01, state); break;
|
||||
case Atari2600DigitalInputJoy2Down: bus_->mos6532_.update_port_input(0, 0x02, state); break;
|
||||
case Atari2600DigitalInputJoy2Left: bus_->mos6532_.update_port_input(0, 0x04, state); break;
|
||||
case Atari2600DigitalInputJoy2Right: bus_->mos6532_.update_port_input(0, 0x08, state); break;
|
||||
|
||||
// TODO: latching
|
||||
case Atari2600DigitalInputJoy1Fire: if(state) bus_->tia_input_value_[0] &= ~0x80; else bus_->tia_input_value_[0] |= 0x80; break;
|
||||
case Atari2600DigitalInputJoy2Fire: if(state) bus_->tia_input_value_[1] &= ~0x80; else bus_->tia_input_value_[1] |= 0x80; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::set_switch_is_enabled(Atari2600Switch input, bool state) {
|
||||
switch(input) {
|
||||
case Atari2600SwitchReset: bus_->mos6532_.update_port_input(1, 0x01, state); break;
|
||||
case Atari2600SwitchSelect: bus_->mos6532_.update_port_input(1, 0x02, state); break;
|
||||
case Atari2600SwitchColour: bus_->mos6532_.update_port_input(1, 0x08, state); break;
|
||||
case Atari2600SwitchLeftPlayerDifficulty: bus_->mos6532_.update_port_input(1, 0x40, state); break;
|
||||
case Atari2600SwitchRightPlayerDifficulty: bus_->mos6532_.update_port_input(1, 0x80, state); break;
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::configure_as_target(const StaticAnalyser::Target &target) {
|
||||
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||
const std::vector<uint8_t> &rom = target.cartridges.front()->get_segments().front().data;
|
||||
switch(target.atari.paging_model) {
|
||||
case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::Cartridge<Cartridge::ActivisionStack>(rom)); break;
|
||||
@ -115,11 +79,69 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - CRT delegate
|
||||
void set_digital_input(Atari2600DigitalInput input, bool state) {
|
||||
switch (input) {
|
||||
case Atari2600DigitalInputJoy1Up: bus_->mos6532_.update_port_input(0, 0x10, state); break;
|
||||
case Atari2600DigitalInputJoy1Down: bus_->mos6532_.update_port_input(0, 0x20, state); break;
|
||||
case Atari2600DigitalInputJoy1Left: bus_->mos6532_.update_port_input(0, 0x40, state); break;
|
||||
case Atari2600DigitalInputJoy1Right: bus_->mos6532_.update_port_input(0, 0x80, state); break;
|
||||
|
||||
void Machine::crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) {
|
||||
case Atari2600DigitalInputJoy2Up: bus_->mos6532_.update_port_input(0, 0x01, state); break;
|
||||
case Atari2600DigitalInputJoy2Down: bus_->mos6532_.update_port_input(0, 0x02, state); break;
|
||||
case Atari2600DigitalInputJoy2Left: bus_->mos6532_.update_port_input(0, 0x04, state); break;
|
||||
case Atari2600DigitalInputJoy2Right: bus_->mos6532_.update_port_input(0, 0x08, state); break;
|
||||
|
||||
// TODO: latching
|
||||
case Atari2600DigitalInputJoy1Fire: if(state) bus_->tia_input_value_[0] &= ~0x80; else bus_->tia_input_value_[0] |= 0x80; break;
|
||||
case Atari2600DigitalInputJoy2Fire: if(state) bus_->tia_input_value_[1] &= ~0x80; else bus_->tia_input_value_[1] |= 0x80; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_switch_is_enabled(Atari2600Switch input, bool state) {
|
||||
switch(input) {
|
||||
case Atari2600SwitchReset: bus_->mos6532_.update_port_input(1, 0x01, state); break;
|
||||
case Atari2600SwitchSelect: bus_->mos6532_.update_port_input(1, 0x02, state); break;
|
||||
case Atari2600SwitchColour: bus_->mos6532_.update_port_input(1, 0x08, state); break;
|
||||
case Atari2600SwitchLeftPlayerDifficulty: bus_->mos6532_.update_port_input(1, 0x40, state); break;
|
||||
case Atari2600SwitchRightPlayerDifficulty: bus_->mos6532_.update_port_input(1, 0x80, state); break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_reset_switch(bool state) {
|
||||
bus_->set_reset_line(state);
|
||||
}
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
void setup_output(float aspect_ratio) {
|
||||
bus_->tia_.reset(new TIA);
|
||||
bus_->speaker_.reset(new Speaker);
|
||||
bus_->speaker_->set_input_rate((float)(get_clock_rate() / (double)CPUTicksPerAudioTick));
|
||||
bus_->tia_->get_crt()->set_delegate(this);
|
||||
}
|
||||
|
||||
void close_output() {
|
||||
bus_.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<Outputs::CRT::CRT> get_crt() {
|
||||
return bus_->tia_->get_crt();
|
||||
}
|
||||
|
||||
std::shared_ptr<Outputs::Speaker> get_speaker() {
|
||||
return bus_->speaker_;
|
||||
}
|
||||
|
||||
void run_for(const Cycles cycles) {
|
||||
bus_->run_for(cycles);
|
||||
}
|
||||
|
||||
// to satisfy Outputs::CRT::Delegate
|
||||
void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) {
|
||||
const size_t number_of_frame_records = sizeof(frame_records_) / sizeof(frame_records_[0]);
|
||||
frame_records_[frame_record_pointer_ % number_of_frame_records].number_of_frames = number_of_frames;
|
||||
frame_records_[frame_record_pointer_ % number_of_frame_records].number_of_unexpected_vertical_syncs = number_of_unexpected_vertical_syncs;
|
||||
@ -154,4 +176,30 @@ void Machine::crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int n
|
||||
set_clock_rate(clock_rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// the bus
|
||||
std::unique_ptr<Bus> bus_;
|
||||
|
||||
// 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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using namespace Atari2600;
|
||||
|
||||
Machine *Machine::Atari2600() {
|
||||
return new Atari2600::ConcreteMachine;
|
||||
}
|
||||
|
||||
Machine::~Machine() {}
|
||||
|
@ -9,59 +9,33 @@
|
||||
#ifndef Atari2600_cpp
|
||||
#define Atari2600_cpp
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "Bus.hpp"
|
||||
#include "PIA.hpp"
|
||||
#include "Speaker.hpp"
|
||||
#include "TIA.hpp"
|
||||
|
||||
#include "../ConfigurationTarget.hpp"
|
||||
#include "../CRTMachine.hpp"
|
||||
|
||||
#include "Atari2600Inputs.h"
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
/*!
|
||||
Models an Atari 2600.
|
||||
*/
|
||||
class Machine:
|
||||
public CRTMachine::Machine,
|
||||
public ConfigurationTarget::Machine,
|
||||
public Outputs::CRT::Delegate {
|
||||
|
||||
public ConfigurationTarget::Machine {
|
||||
public:
|
||||
Machine();
|
||||
~Machine();
|
||||
virtual ~Machine();
|
||||
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
void switch_region();
|
||||
/// Creates and returns an Atari 2600 on the heap.
|
||||
static Machine *Atari2600();
|
||||
|
||||
void set_digital_input(Atari2600DigitalInput input, bool state);
|
||||
void set_switch_is_enabled(Atari2600Switch input, bool state);
|
||||
void set_reset_line(bool state) { bus_->set_reset_line(state); }
|
||||
/// Sets @c input to @c state.
|
||||
virtual void set_digital_input(Atari2600DigitalInput input, bool state) = 0;
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
virtual void setup_output(float aspect_ratio);
|
||||
virtual void close_output();
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return bus_->tia_->get_crt(); }
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return bus_->speaker_; }
|
||||
virtual void run_for(const Cycles cycles) { bus_->run_for(cycles); }
|
||||
/// Sets the switch @c input to @c state.
|
||||
virtual void set_switch_is_enabled(Atari2600Switch input, bool state) = 0;
|
||||
|
||||
// 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:
|
||||
// the bus
|
||||
std::unique_ptr<Bus> bus_;
|
||||
|
||||
// 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_;
|
||||
// Presses or releases the reset button.
|
||||
virtual void set_reset_switch(bool state) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,14 @@
|
||||
#import "CSMachine+Subclassing.h"
|
||||
|
||||
@implementation CSAtari2600 {
|
||||
Atari2600::Machine _atari2600;
|
||||
std::unique_ptr<Atari2600::Machine> _atari2600;
|
||||
}
|
||||
|
||||
- (CRTMachine::Machine * const)machine {
|
||||
if(!_atari2600) {
|
||||
_atari2600.reset(Atari2600::Machine::Atari2600());
|
||||
}
|
||||
return _atari2600.get();
|
||||
}
|
||||
|
||||
- (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed {
|
||||
@ -25,19 +32,19 @@
|
||||
case CSJoystickDirectionRight: input = pad ? Atari2600DigitalInputJoy2Right : Atari2600DigitalInputJoy1Right; break;
|
||||
}
|
||||
@synchronized(self) {
|
||||
_atari2600.set_digital_input(input, isPressed ? true : false);
|
||||
_atari2600->set_digital_input(input, isPressed ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setButtonAtIndex:(NSUInteger)button onPad:(NSUInteger)pad isPressed:(BOOL)isPressed {
|
||||
@synchronized(self) {
|
||||
_atari2600.set_digital_input(pad ? Atari2600DigitalInputJoy2Fire : Atari2600DigitalInputJoy1Fire, isPressed ? true : false);
|
||||
_atari2600->set_digital_input(pad ? Atari2600DigitalInputJoy2Fire : Atari2600DigitalInputJoy1Fire, isPressed ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setResetLineEnabled:(BOOL)enabled {
|
||||
@synchronized(self) {
|
||||
_atari2600.set_reset_line(enabled ? true : false);
|
||||
_atari2600->set_reset_switch(enabled ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,40 +54,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (CRTMachine::Machine * const)machine {
|
||||
return &_atari2600;
|
||||
}
|
||||
|
||||
#pragma mark - Switches
|
||||
|
||||
- (void)setColourButton:(BOOL)colourButton {
|
||||
_colourButton = colourButton;
|
||||
@synchronized(self) {
|
||||
_atari2600.set_switch_is_enabled(Atari2600SwitchColour, colourButton);
|
||||
_atari2600->set_switch_is_enabled(Atari2600SwitchColour, colourButton);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setLeftPlayerDifficultyButton:(BOOL)leftPlayerDifficultyButton {
|
||||
_leftPlayerDifficultyButton = leftPlayerDifficultyButton;
|
||||
@synchronized(self) {
|
||||
_atari2600.set_switch_is_enabled(Atari2600SwitchLeftPlayerDifficulty, leftPlayerDifficultyButton);
|
||||
_atari2600->set_switch_is_enabled(Atari2600SwitchLeftPlayerDifficulty, leftPlayerDifficultyButton);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRightPlayerDifficultyButton:(BOOL)rightPlayerDifficultyButton {
|
||||
_rightPlayerDifficultyButton = rightPlayerDifficultyButton;
|
||||
@synchronized(self) {
|
||||
_atari2600.set_switch_is_enabled(Atari2600SwitchRightPlayerDifficulty, rightPlayerDifficultyButton);
|
||||
_atari2600->set_switch_is_enabled(Atari2600SwitchRightPlayerDifficulty, rightPlayerDifficultyButton);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)toggleSwitch:(Atari2600Switch)toggleSwitch {
|
||||
@synchronized(self) {
|
||||
_atari2600.set_switch_is_enabled(toggleSwitch, true);
|
||||
_atari2600->set_switch_is_enabled(toggleSwitch, true);
|
||||
}
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
@synchronized(self) {
|
||||
_atari2600.set_switch_is_enabled(toggleSwitch, false);
|
||||
_atari2600->set_switch_is_enabled(toggleSwitch, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user