From 204d5cc96458b28da90655bbcaa91c51400d16a8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 25 Feb 2018 19:08:50 -0500 Subject: [PATCH] Extends JoystickMachine protocol to cover ColecoVision use case. Also thereby implements input on the ColecoVision, in theory at least. No input is being fed though, so... --- Inputs/Joystick.hpp | 43 ++++++++-- Machines/Atari2600/Atari2600.cpp | 16 +++- Machines/ColecoVision/ColecoVision.cpp | 104 ++++++++++++++++++++++++- Machines/Commodore/Vic-20/Vic20.cpp | 14 +++- 4 files changed, 163 insertions(+), 14 deletions(-) diff --git a/Inputs/Joystick.hpp b/Inputs/Joystick.hpp index 364941e8d..f7c995cf6 100644 --- a/Inputs/Joystick.hpp +++ b/Inputs/Joystick.hpp @@ -21,18 +21,45 @@ class Joystick { public: virtual ~Joystick() {} - enum class DigitalInput { - Up, Down, Left, Right, Fire + struct DigitalInput { + enum Type { + Up, Down, Left, Right, Fire, + Key + } type; + union { + struct { + int index; + } control; + struct { + wchar_t symbol; + } key; + } info; + + DigitalInput(Type type, int index = 0) : type(type) { + info.control.index = index; + } + DigitalInput(wchar_t symbol) : type(Key) { + info.key.symbol = symbol; + } + + bool operator == (const DigitalInput &rhs) { + if(rhs.type != type) return false; + if(rhs.type == Key) { + return rhs.info.key.symbol == info.key.symbol; + } else { + return rhs.info.control.index == info.control.index; + } + } }; + virtual std::vector get_inputs() = 0; + // Host interface. - virtual void set_digital_input(DigitalInput digital_input, bool is_active) = 0; + virtual void set_digital_input(const DigitalInput &digital_input, bool is_active) = 0; virtual void reset_all_inputs() { - set_digital_input(DigitalInput::Up, false); - set_digital_input(DigitalInput::Down, false); - set_digital_input(DigitalInput::Left, false); - set_digital_input(DigitalInput::Right, false); - set_digital_input(DigitalInput::Fire, false); + for(const auto &input: get_inputs()) { + set_digital_input(input, false); + } } }; diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 255d99b45..70aa8753d 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -36,8 +36,18 @@ class Joystick: public Inputs::Joystick { Joystick(Bus *bus, std::size_t shift, std::size_t fire_tia_input) : bus_(bus), shift_(shift), fire_tia_input_(fire_tia_input) {} - void set_digital_input(DigitalInput digital_input, bool is_active) { - switch(digital_input) { + std::vector get_inputs() override { + return { + DigitalInput(DigitalInput::Up), + DigitalInput(DigitalInput::Down), + DigitalInput(DigitalInput::Left), + DigitalInput(DigitalInput::Right), + DigitalInput(DigitalInput::Fire) + }; + } + + void set_digital_input(const DigitalInput &digital_input, bool is_active) override { + switch(digital_input.type) { case DigitalInput::Up: bus_->mos6532_.update_port_input(0, 0x10 >> shift_, is_active); break; case DigitalInput::Down: bus_->mos6532_.update_port_input(0, 0x20 >> shift_, is_active); break; case DigitalInput::Left: bus_->mos6532_.update_port_input(0, 0x40 >> shift_, is_active); break; @@ -50,6 +60,8 @@ class Joystick: public Inputs::Joystick { else bus_->tia_input_value_[fire_tia_input_] |= 0x80; break; + + default: break; } } diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index d38f0dd9b..c8593b4cf 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -12,23 +12,104 @@ #include "../../Components/9918/9918.hpp" -#include "../CRTMachine.hpp" #include "../ConfigurationTarget.hpp" +#include "../CRTMachine.hpp" +#include "../JoystickMachine.hpp" #include "../../ClockReceiver/ForceInline.hpp" namespace Coleco { namespace Vision { +class Joystick: public Inputs::Joystick { + public: + std::vector get_inputs() override { + return { + DigitalInput(DigitalInput::Up), + DigitalInput(DigitalInput::Down), + DigitalInput(DigitalInput::Left), + DigitalInput(DigitalInput::Right), + + DigitalInput(DigitalInput::Fire, 0), + DigitalInput(DigitalInput::Fire, 1), + + DigitalInput('0'), DigitalInput('1'), DigitalInput('2'), + DigitalInput('3'), DigitalInput('4'), DigitalInput('5'), + DigitalInput('6'), DigitalInput('7'), DigitalInput('8'), + DigitalInput('9'), DigitalInput('*'), DigitalInput('#'), + }; + } + + void set_digital_input(const DigitalInput &digital_input, bool is_active) override { + switch(digital_input.type) { + default: return; + + case DigitalInput::Key: + if(!is_active) keypad_ |= 0xf; + else { + uint8_t mask = 0xf; + switch(digital_input.info.key.symbol) { + case '0': mask = 0x5; break; + case '1': mask = 0xb; break; + case '2': mask = 0xe; break; + case '3': mask = 0x3; break; + case '4': mask = 0x4; break; + case '5': mask = 0xc; break; + case '6': mask = 0x7; break; + case '7': mask = 0xa; break; + case '8': mask = 0x8; break; + case '9': mask = 0xd; break; + case '*': mask = 0x9; break; + case '#': mask = 0x6; break; + default: break; + } + keypad_ = (keypad_ & 0xf0) | mask; + } + break; + + case DigitalInput::Up: if(is_active) direction_ = direction_ &= ~0x08; else direction_ |= 0x08; break; + case DigitalInput::Down: if(is_active) direction_ = direction_ &= ~0x02; else direction_ |= 0x02; break; + case DigitalInput::Left: if(is_active) direction_ = direction_ &= ~0x01; else direction_ |= 0x01; break; + case DigitalInput::Right: if(is_active) direction_ = direction_ &= ~0x04; else direction_ |= 0x04; break; + case DigitalInput::Fire: + switch(digital_input.info.control.index) { + default: break; + case 0: if(is_active) direction_ = direction_ &= ~0x10; else direction_ |= 0x10; break; + case 1: if(is_active) keypad_ = keypad_ &= ~0x10; else keypad_ |= 0x10; break; + } + break; + } + } + + uint8_t get_direction_input() { + return direction_; + } + + uint8_t get_keypad_input() { + return keypad_; + } + + private: + uint8_t direction_ = 0xff; + uint8_t keypad_ = 0xff; +}; + class ConcreteMachine: public Machine, public CPU::Z80::BusHandler, public CRTMachine::Machine, - public ConfigurationTarget::Machine { + public ConfigurationTarget::Machine, + public JoystickMachine::Machine { public: ConcreteMachine() : z80_(*this) { set_clock_rate(3579545); + joysticks_.emplace_back(new Joystick); + joysticks_.emplace_back(new Joystick); + } + + std::vector> &get_joysticks() override { + return joysticks_; } void setup_output(float aspect_ratio) override { @@ -121,6 +202,14 @@ class ConcreteMachine: time_until_interrupt_ = vdp_->get_time_until_interrupt(); break; + case 7: + if(joysticks_in_keypad_mode_) { + *cycle.value = static_cast(joysticks_[address&1].get())->get_keypad_input(); + } else { + *cycle.value = static_cast(joysticks_[address&1].get())->get_direction_input(); + } + break; + default: *cycle.value = 0xff; break; @@ -129,6 +218,10 @@ class ConcreteMachine: case CPU::Z80::PartialMachineCycle::Output: switch((address >> 5) & 7) { + case 4: case 6: + joysticks_in_keypad_mode_ = ((address >> 5) & 7) == 4; + break; + case 5: vdp_->run_for(time_since_vdp_update_.flush()); vdp_->set_register(address, *cycle.value); @@ -136,6 +229,10 @@ class ConcreteMachine: time_until_interrupt_ = vdp_->get_time_until_interrupt(); break; + case 7: + // TODO: write to audio. + break; + default: break; } break; @@ -160,6 +257,9 @@ class ConcreteMachine: std::vector cartridge_; uint8_t ram_[1024]; + std::vector> joysticks_; + bool joysticks_in_keypad_mode_ = false; + HalfCycles time_since_vdp_update_; HalfCycles time_until_interrupt_; }; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index d0edf7cf0..f047f0780 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -252,9 +252,19 @@ class Joystick: public Inputs::Joystick { user_port_via_port_handler_(user_port_via_port_handler), keyboard_via_port_handler_(keyboard_via_port_handler) {} - void set_digital_input(DigitalInput digital_input, bool is_active) override { + std::vector get_inputs() override { + return { + DigitalInput(DigitalInput::Up), + DigitalInput(DigitalInput::Down), + DigitalInput(DigitalInput::Left), + DigitalInput(DigitalInput::Right), + DigitalInput(DigitalInput::Fire) + }; + } + + void set_digital_input(const DigitalInput &digital_input, bool is_active) override { JoystickInput mapped_input; - switch (digital_input) { + switch(digital_input.type) { default: return; case DigitalInput::Up: mapped_input = Up; break; case DigitalInput::Down: mapped_input = Down; break;