1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-26 10:29:31 +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:
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<DigitalInput> 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);
}
}
};

View File

@ -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<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 {
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;
}
}

View File

@ -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<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:
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<std::unique_ptr<Inputs::Joystick>> &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<Joystick *>(joysticks_[address&1].get())->get_keypad_input();
} else {
*cycle.value = static_cast<Joystick *>(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<uint8_t> cartridge_;
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_until_interrupt_;
};

View File

@ -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<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;
switch (digital_input) {
switch(digital_input.type) {
default: return;
case DigitalInput::Up: mapped_input = Up; break;
case DigitalInput::Down: mapped_input = Down; break;