From 2c25135d8a0a4e295f430689fc5ac09d4de0dc0b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 9 Nov 2019 18:19:05 -0500 Subject: [PATCH 1/4] Fixes const correctness for joystick machines; the ST is now one such. --- .../MultiMachine/Implementation/MultiJoystickMachine.cpp | 2 +- .../MultiMachine/Implementation/MultiJoystickMachine.hpp | 2 +- Machines/AmstradCPC/AmstradCPC.cpp | 4 ++-- Machines/Apple/AppleII/AppleII.cpp | 2 +- Machines/Atari/2600/Atari2600.cpp | 2 +- Machines/Atari/ST/AtariST.cpp | 7 +++++++ Machines/Atari/ST/IntelligentKeyboard.hpp | 8 ++++++++ Machines/ColecoVision/ColecoVision.cpp | 2 +- Machines/Commodore/Vic-20/Vic20.cpp | 2 +- Machines/JoystickMachine.hpp | 2 +- Machines/MSX/MSX.cpp | 4 ++-- Machines/MasterSystem/MasterSystem.cpp | 2 +- OSBindings/Mac/Clock Signal/Machine/CSMachine.mm | 6 +++--- OSBindings/SDL/main.cpp | 4 ++-- 14 files changed, 32 insertions(+), 17 deletions(-) diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp index 526b43749..70255b13e 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp @@ -81,6 +81,6 @@ MultiJoystickMachine::MultiJoystickMachine(const std::vector> &MultiJoystickMachine::get_joysticks() { +const std::vector> &MultiJoystickMachine::get_joysticks() { return joysticks_; } diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp index f755d3061..6425a9a0a 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp @@ -28,7 +28,7 @@ class MultiJoystickMachine: public JoystickMachine::Machine { MultiJoystickMachine(const std::vector> &machines); // Below is the standard JoystickMachine::Machine interface; see there for documentation. - std::vector> &get_joysticks() override; + const std::vector> &get_joysticks() override; private: std::vector> joysticks_; diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 6ebd9d5b6..bf869cf12 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -604,7 +604,7 @@ class KeyboardState: public GI::AY38910::PortHandler { memset(rows_, 0xff, sizeof(rows_)); } - std::vector> &get_joysticks() { + const std::vector> &get_joysticks() { return joysticks_; } @@ -1093,7 +1093,7 @@ template class ConcreteMachine: } // MARK: - Joysticks - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return key_state_.get_joysticks(); } diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 3757092e1..f561059ca 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -893,7 +893,7 @@ template class ConcreteMachine: } // MARK: JoystickMachine - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } }; diff --git a/Machines/Atari/2600/Atari2600.cpp b/Machines/Atari/2600/Atari2600.cpp index 3b2afe210..f1bce4903 100644 --- a/Machines/Atari/2600/Atari2600.cpp +++ b/Machines/Atari/2600/Atari2600.cpp @@ -124,7 +124,7 @@ class ConcreteMachine: joysticks_.emplace_back(new Joystick(bus_.get(), 4, 1)); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/Machines/Atari/ST/AtariST.cpp b/Machines/Atari/ST/AtariST.cpp index e100043f8..413b94acb 100644 --- a/Machines/Atari/ST/AtariST.cpp +++ b/Machines/Atari/ST/AtariST.cpp @@ -9,6 +9,7 @@ #include "AtariST.hpp" #include "../../CRTMachine.hpp" +#include "../../JoystickMachine.hpp" #include "../../KeyboardMachine.hpp" #include "../../MouseMachine.hpp" #include "../../MediaTarget.hpp" @@ -49,6 +50,7 @@ class ConcreteMachine: public Motorola::MFP68901::MFP68901::InterruptDelegate, public DMAController::Delegate, public MouseMachine::Machine, + public JoystickMachine::Machine, public KeyboardMachine::MappedMachine, public Activity::Source, public MediaTarget::Machine, @@ -527,6 +529,11 @@ class ConcreteMachine: return &keyboard_mapper_; } + // MARK: - JoystickMachine + const std::vector> &get_joysticks() final { + return ikbd_.get_joysticks(); + } + // MARK: - AYPortHandler void set_port_output(bool port_b, uint8_t value) final { if(port_b) { diff --git a/Machines/Atari/ST/IntelligentKeyboard.hpp b/Machines/Atari/ST/IntelligentKeyboard.hpp index f81cfcc08..77d5b0642 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.hpp +++ b/Machines/Atari/ST/IntelligentKeyboard.hpp @@ -13,10 +13,13 @@ #include "../../../Components/Serial/Line.hpp" #include "../../KeyboardMachine.hpp" +#include "../../../Inputs/Joystick.hpp" #include "../../../Inputs/Mouse.hpp" #include #include +#include +#include namespace Atari { namespace ST { @@ -61,6 +64,10 @@ class IntelligentKeyboard: uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) final; }; + const std::vector> &get_joysticks() { + return joysticks_; + } + private: // MARK: - Key queue. std::mutex key_queue_mutex_; @@ -128,6 +135,7 @@ class IntelligentKeyboard: enum class JoystickMode { Disabled, Event, Interrogation } joystick_mode_ = JoystickMode::Event; + std::vector> joysticks_; }; } diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index 371cca534..c3386d633 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -177,7 +177,7 @@ class ConcreteMachine: audio_queue_.flush(); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 4c65dc304..cb7682c80 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -494,7 +494,7 @@ class ConcreteMachine: keyboard_via_port_handler_->clear_all_keys(); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/Machines/JoystickMachine.hpp b/Machines/JoystickMachine.hpp index 15c74e2eb..ae884cc25 100644 --- a/Machines/JoystickMachine.hpp +++ b/Machines/JoystickMachine.hpp @@ -16,7 +16,7 @@ namespace JoystickMachine { class Machine { public: - virtual std::vector> &get_joysticks() = 0; + virtual const std::vector> &get_joysticks() = 0; }; } diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 0c00ab83d..bed05c068 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -89,7 +89,7 @@ class AYPortHandler: public GI::AY38910::PortHandler { return 0xff; } - std::vector> &get_joysticks() { + const std::vector> &get_joysticks() { return joysticks_; } @@ -686,7 +686,7 @@ class ConcreteMachine: } // MARK: - Joysticks - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return ay_port_handler_.get_joysticks(); } diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index a005b4e3d..b32453eda 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -340,7 +340,7 @@ class ConcreteMachine: audio_queue_.perform(); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index a8160f139..5723930f6 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -268,7 +268,7 @@ struct ActivityObserver: public Activity::Observer { // Until then, apply a default mapping. size_t c = 0; - std::vector> &machine_joysticks = _joystickMachine->get_joysticks(); + auto &machine_joysticks = _joystickMachine->get_joysticks(); for(CSJoystick *joystick in _joystickManager.joysticks) { size_t target = c % machine_joysticks.size(); ++c; @@ -373,7 +373,7 @@ struct ActivityObserver: public Activity::Observer { @synchronized(self) { _joystickManager = joystickManager; if(_joystickMachine) { - std::vector> &machine_joysticks = _joystickMachine->get_joysticks(); + auto &machine_joysticks = _joystickMachine->get_joysticks(); for(const auto &joystick: machine_joysticks) { joystick->reset_all_inputs(); } @@ -467,7 +467,7 @@ struct ActivityObserver: public Activity::Observer { auto joystick_machine = _machine->joystick_machine(); if(self.inputMode == CSMachineKeyboardInputModeJoystick && joystick_machine) { @synchronized(self) { - std::vector> &joysticks = joystick_machine->get_joysticks(); + auto &joysticks = joystick_machine->get_joysticks(); if(!joysticks.empty()) { // Convert to a C++ bool so that the following calls are resolved correctly even if overloaded. bool is_pressed = !!isPressed; diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index cde2106fa..337c5c26b 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -741,7 +741,7 @@ int main(int argc, char *argv[]) { JoystickMachine::Machine *const joystick_machine = machine->joystick_machine(); if(joystick_machine) { - std::vector> &joysticks = joystick_machine->get_joysticks(); + auto &joysticks = joystick_machine->get_joysticks(); if(!joysticks.empty()) { switch(event.key.keysym.scancode) { case SDL_SCANCODE_LEFT: joysticks[0]->set_input(Inputs::Joystick::Input::Left, is_pressed); break; @@ -791,7 +791,7 @@ int main(int argc, char *argv[]) { // Push new joystick state, if any. JoystickMachine::Machine *const joystick_machine = machine->joystick_machine(); if(joystick_machine) { - std::vector> &machine_joysticks = joystick_machine->get_joysticks(); + auto &machine_joysticks = joystick_machine->get_joysticks(); for(size_t c = 0; c < joysticks.size(); ++c) { size_t target = c % machine_joysticks.size(); From 8e9428623ecd5e0c50389c4a3cafa8d72ad5f0d4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 9 Nov 2019 18:39:22 -0500 Subject: [PATCH 2/4] Adds joystick events to the Atari ST. --- Machines/Atari/ST/IntelligentKeyboard.cpp | 26 ++++++++++++--- Machines/Atari/ST/IntelligentKeyboard.hpp | 39 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/Machines/Atari/ST/IntelligentKeyboard.cpp b/Machines/Atari/ST/IntelligentKeyboard.cpp index c644508b5..fe21b9866 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.cpp +++ b/Machines/Atari/ST/IntelligentKeyboard.cpp @@ -14,6 +14,10 @@ IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &outp input.set_read_delegate(this, Storage::Time(2, 15625)); output_line_.set_writer_clock_rate(15625); + // Add two joysticks into the mix. + joysticks_.emplace_back(new Joystick); + joysticks_.emplace_back(new Joystick); + mouse_button_state_ = 0; mouse_movement_[0] = 0; mouse_movement_[1] = 0; @@ -40,7 +44,7 @@ ClockingHint::Preference IntelligentKeyboard::preferred_clocking() { } void IntelligentKeyboard::run_for(HalfCycles duration) { - // Take this opportunity to check for mouse and keyboard events, + // Take this opportunity to check for joystick, mouse and keyboard events, // which will have been received asynchronously. if(mouse_mode_ == MouseMode::Relative) { const int captured_movement[2] = { mouse_movement_[0].load(), mouse_movement_[1].load() }; @@ -55,7 +59,7 @@ void IntelligentKeyboard::run_for(HalfCycles duration) { post_relative_mouse_event(captured_movement[0], captured_movement[1]); } } else { - + // TODO: absolute-mode mouse updates. } // Forward key changes; implicit assumption here: mutexs are cheap while there's @@ -68,6 +72,17 @@ void IntelligentKeyboard::run_for(HalfCycles duration) { key_queue_.clear(); } + // Check for joystick changes. + for(size_t c = 0; c < 2; ++c) { + const auto joystick = static_cast(joysticks_[c].get()); + if(joystick->has_event()) { + output_bytes({ + uint8_t(0xfe | c), + joystick->get_state() + }); + } + } + output_line_.advance_writer(duration); } @@ -346,9 +361,12 @@ void IntelligentKeyboard::set_joystick_interrogation_mode() { } void IntelligentKeyboard::interrogate_joysticks() { + const auto joystick1 = static_cast(joysticks_[0].get()); + const auto joystick2 = static_cast(joysticks_[1].get()); + output_bytes({ 0xfd, - 0x00, - 0x00 + joystick1->get_state(), + joystick2->get_state() }); } diff --git a/Machines/Atari/ST/IntelligentKeyboard.hpp b/Machines/Atari/ST/IntelligentKeyboard.hpp index 77d5b0642..f7f62a537 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.hpp +++ b/Machines/Atari/ST/IntelligentKeyboard.hpp @@ -135,6 +135,45 @@ class IntelligentKeyboard: enum class JoystickMode { Disabled, Event, Interrogation } joystick_mode_ = JoystickMode::Event; + + class Joystick: public Inputs::ConcreteJoystick { + public: + Joystick() : + ConcreteJoystick({ + Input(Input::Up), + Input(Input::Down), + Input(Input::Left), + Input(Input::Right), + Input(Input::Fire, 0), + }) {} + + void did_set_input(const Input &input, bool is_active) override { + uint8_t mask = 0; + switch(input.type) { + default: return; + case Input::Up: mask = 0x01; break; + case Input::Down: mask = 0x02; break; + case Input::Left: mask = 0x04; break; + case Input::Right: mask = 0x08; break; + case Input::Fire: mask = 0x80; break; + } + + if(is_active) state_ &= ~mask; else state_ |= mask; + } + + uint8_t get_state() { + returned_state_ = state_; + return state_; + } + + bool has_event() { + return returned_state_ != state_; + } + + private: + uint8_t state_ = 0x8f; + uint8_t returned_state_ = 0x8f; + }; std::vector> joysticks_; }; From 7ae090210327510a4b3b9db96e3a2b732225effc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 9 Nov 2019 20:10:54 -0500 Subject: [PATCH 3/4] Adds additional joystick commands to the dispatcher. --- Machines/Atari/ST/IntelligentKeyboard.cpp | 37 ++++++++++++++++++++--- Machines/Atari/ST/IntelligentKeyboard.hpp | 14 +++++++-- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/Machines/Atari/ST/IntelligentKeyboard.cpp b/Machines/Atari/ST/IntelligentKeyboard.cpp index fe21b9866..17975563e 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.cpp +++ b/Machines/Atari/ST/IntelligentKeyboard.cpp @@ -167,10 +167,30 @@ void IntelligentKeyboard::dispatch_command(uint8_t command) { case 0x12: disable_mouse(); break; case 0x13: pause(); break; - case 0x14: set_joystick_event_mode(); break; - case 0x15: set_joystick_interrogation_mode(); break; - case 0x16: interrogate_joysticks(); break; - case 0x1a: disable_joysticks(); break; + /* Joystick commands. */ + case 0x14: set_joystick_event_mode(); break; + case 0x15: set_joystick_interrogation_mode(); break; + case 0x16: interrogate_joysticks(); break; + case 0x17: + if(command_sequence_.size() != 2) return; + set_joystick_monitoring_mode(command_sequence_[1]); + break; + case 0x18: set_joystick_fire_button_monitoring_mode(); break; + case 0x19: { + if(command_sequence_.size() != 7) return; + + VelocityThreshold horizontal, vertical; + horizontal.threshold = command_sequence_[1]; + horizontal.prior_rate = command_sequence_[3]; + horizontal.post_rate = command_sequence_[5]; + + vertical.threshold = command_sequence_[2]; + vertical.prior_rate = command_sequence_[4]; + vertical.post_rate = command_sequence_[6]; + + set_joystick_keycode_mode(horizontal, vertical); + } break; + case 0x1a: disable_joysticks(); break; } // There was no premature exit, so a complete command sequence must have been satisfied. @@ -370,3 +390,12 @@ void IntelligentKeyboard::interrogate_joysticks() { joystick2->get_state() }); } + +void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t rate) { +} + +void IntelligentKeyboard::set_joystick_fire_button_monitoring_mode() { +} + +void IntelligentKeyboard::set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical) { +} diff --git a/Machines/Atari/ST/IntelligentKeyboard.hpp b/Machines/Atari/ST/IntelligentKeyboard.hpp index f7f62a537..488bc5aef 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.hpp +++ b/Machines/Atari/ST/IntelligentKeyboard.hpp @@ -130,6 +130,14 @@ class IntelligentKeyboard: void disable_joysticks(); void set_joystick_event_mode(); void set_joystick_interrogation_mode(); + void set_joystick_monitoring_mode(uint8_t rate); + void set_joystick_fire_button_monitoring_mode(); + struct VelocityThreshold { + uint8_t threshold; + uint8_t prior_rate; + uint8_t post_rate; + }; + void set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical); void interrogate_joysticks(); enum class JoystickMode { @@ -158,7 +166,7 @@ class IntelligentKeyboard: case Input::Fire: mask = 0x80; break; } - if(is_active) state_ &= ~mask; else state_ |= mask; + if(is_active) state_ |= mask; else state_ &= ~mask; } uint8_t get_state() { @@ -171,8 +179,8 @@ class IntelligentKeyboard: } private: - uint8_t state_ = 0x8f; - uint8_t returned_state_ = 0x8f; + uint8_t state_ = 0x00; + uint8_t returned_state_ = 0x00; }; std::vector> joysticks_; }; From 072b0266af70ce51eacad08831950e5ebcb2ea8a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 9 Nov 2019 20:12:09 -0500 Subject: [PATCH 4/4] It seems status reads are not required to clear the interrupt line. --- Components/6850/6850.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Components/6850/6850.cpp b/Components/6850/6850.cpp index c61c4bb4d..9b08ca8eb 100644 --- a/Components/6850/6850.cpp +++ b/Components/6850/6850.cpp @@ -25,7 +25,6 @@ uint8_t ACIA::read(int address) { received_data_ |= NoValueMask; return uint8_t(received_data_); } else { - clear_interrupt_cause(StatusNeedsRead); return ((received_data_ & NoValueMask) ? 0x00 : 0x01) | ((next_transmission_ == NoValueMask) ? 0x02 : 0x00) | @@ -176,7 +175,7 @@ void ACIA::set_interrupt_delegate(InterruptDelegate *delegate) { void ACIA::add_interrupt_cause(int cause) { const bool is_changing_state = !interrupt_causes_; - interrupt_causes_ |= cause | StatusNeedsRead; + interrupt_causes_ |= cause; if(interrupt_delegate_ && is_changing_state) interrupt_delegate_->acia6850_did_change_interrupt_status(this); }