1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-29 00:29:34 +00:00

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...
This commit is contained in:
Thomas Harte 2018-02-25 19:08:50 -05:00
parent 23d15a4d6c
commit 204d5cc964
4 changed files with 163 additions and 14 deletions

View File

@ -21,18 +21,45 @@ class Joystick {
public: public:
virtual ~Joystick() {} virtual ~Joystick() {}
enum class DigitalInput { struct DigitalInput {
Up, Down, Left, Right, Fire 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<DigitalInput> get_inputs() = 0;
// Host interface. // 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() { virtual void reset_all_inputs() {
set_digital_input(DigitalInput::Up, false); for(const auto &input: get_inputs()) {
set_digital_input(DigitalInput::Down, false); set_digital_input(input, false);
set_digital_input(DigitalInput::Left, false); }
set_digital_input(DigitalInput::Right, false);
set_digital_input(DigitalInput::Fire, false);
} }
}; };

View File

@ -36,8 +36,18 @@ class Joystick: public Inputs::Joystick {
Joystick(Bus *bus, std::size_t shift, std::size_t fire_tia_input) : Joystick(Bus *bus, std::size_t shift, std::size_t fire_tia_input) :
bus_(bus), shift_(shift), fire_tia_input_(fire_tia_input) {} bus_(bus), shift_(shift), fire_tia_input_(fire_tia_input) {}
void set_digital_input(DigitalInput digital_input, bool is_active) { std::vector<DigitalInput> get_inputs() override {
switch(digital_input) { 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::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::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; case DigitalInput::Left: bus_->mos6532_.update_port_input(0, 0x40 >> shift_, is_active); break;
@ -50,6 +60,8 @@ class Joystick: public Inputs::Joystick {
else else
bus_->tia_input_value_[fire_tia_input_] |= 0x80; bus_->tia_input_value_[fire_tia_input_] |= 0x80;
break; break;
default: break;
} }
} }

View File

@ -12,23 +12,104 @@
#include "../../Components/9918/9918.hpp" #include "../../Components/9918/9918.hpp"
#include "../CRTMachine.hpp"
#include "../ConfigurationTarget.hpp" #include "../ConfigurationTarget.hpp"
#include "../CRTMachine.hpp"
#include "../JoystickMachine.hpp"
#include "../../ClockReceiver/ForceInline.hpp" #include "../../ClockReceiver/ForceInline.hpp"
namespace Coleco { namespace Coleco {
namespace Vision { namespace Vision {
class Joystick: public Inputs::Joystick {
public:
std::vector<DigitalInput> 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: class ConcreteMachine:
public Machine, public Machine,
public CPU::Z80::BusHandler, public CPU::Z80::BusHandler,
public CRTMachine::Machine, public CRTMachine::Machine,
public ConfigurationTarget::Machine { public ConfigurationTarget::Machine,
public JoystickMachine::Machine {
public: public:
ConcreteMachine() : z80_(*this) { ConcreteMachine() : z80_(*this) {
set_clock_rate(3579545); set_clock_rate(3579545);
joysticks_.emplace_back(new Joystick);
joysticks_.emplace_back(new Joystick);
}
std::vector<std::unique_ptr<Inputs::Joystick>> &get_joysticks() override {
return joysticks_;
} }
void setup_output(float aspect_ratio) override { void setup_output(float aspect_ratio) override {
@ -121,6 +202,14 @@ class ConcreteMachine:
time_until_interrupt_ = vdp_->get_time_until_interrupt(); time_until_interrupt_ = vdp_->get_time_until_interrupt();
break; break;
case 7:
if(joysticks_in_keypad_mode_) {
*cycle.value = static_cast<Joystick *>(joysticks_[address&1].get())->get_keypad_input();
} else {
*cycle.value = static_cast<Joystick *>(joysticks_[address&1].get())->get_direction_input();
}
break;
default: default:
*cycle.value = 0xff; *cycle.value = 0xff;
break; break;
@ -129,6 +218,10 @@ class ConcreteMachine:
case CPU::Z80::PartialMachineCycle::Output: case CPU::Z80::PartialMachineCycle::Output:
switch((address >> 5) & 7) { switch((address >> 5) & 7) {
case 4: case 6:
joysticks_in_keypad_mode_ = ((address >> 5) & 7) == 4;
break;
case 5: case 5:
vdp_->run_for(time_since_vdp_update_.flush()); vdp_->run_for(time_since_vdp_update_.flush());
vdp_->set_register(address, *cycle.value); vdp_->set_register(address, *cycle.value);
@ -136,6 +229,10 @@ class ConcreteMachine:
time_until_interrupt_ = vdp_->get_time_until_interrupt(); time_until_interrupt_ = vdp_->get_time_until_interrupt();
break; break;
case 7:
// TODO: write to audio.
break;
default: break; default: break;
} }
break; break;
@ -160,6 +257,9 @@ class ConcreteMachine:
std::vector<uint8_t> cartridge_; std::vector<uint8_t> cartridge_;
uint8_t ram_[1024]; uint8_t ram_[1024];
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
bool joysticks_in_keypad_mode_ = false;
HalfCycles time_since_vdp_update_; HalfCycles time_since_vdp_update_;
HalfCycles time_until_interrupt_; HalfCycles time_until_interrupt_;
}; };

View File

@ -252,9 +252,19 @@ class Joystick: public Inputs::Joystick {
user_port_via_port_handler_(user_port_via_port_handler), user_port_via_port_handler_(user_port_via_port_handler),
keyboard_via_port_handler_(keyboard_via_port_handler) {} keyboard_via_port_handler_(keyboard_via_port_handler) {}
void set_digital_input(DigitalInput digital_input, bool is_active) override { std::vector<DigitalInput> 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; JoystickInput mapped_input;
switch (digital_input) { switch(digital_input.type) {
default: return; default: return;
case DigitalInput::Up: mapped_input = Up; break; case DigitalInput::Up: mapped_input = Up; break;
case DigitalInput::Down: mapped_input = Down; break; case DigitalInput::Down: mapped_input = Down; break;