openMSX
ColecoJoystickIO.cc
Go to the documentation of this file.
1 #include "ColecoJoystickIO.hh"
2 #include "MSXMotherBoard.hh"
3 #include "Reactor.hh"
4 #include "JoystickPort.hh"
5 #include "Math.hh"
6 #include "serialize.hh"
7 
8 namespace openmsx {
9 
11  : MSXDevice(config)
12  , keyboard(
13  config.getMotherBoard(),
14  config.getMotherBoard().getScheduler(),
15  config.getMotherBoard().getCommandController(),
16  config.getMotherBoard().getReactor().getEventDistributor(),
17  config.getMotherBoard().getMSXEventDistributor(),
18  config.getMotherBoard().getStateChangeDistributor(),
19  Keyboard::MATRIX_CVJOY,
20  config)
21 {
22  MSXMotherBoard& motherBoard = getMotherBoard();
23  auto time = getCurrentTime();
24  for (unsigned i = 0; i < 2; i++) {
25  ports[i] = &motherBoard.getJoystickPort(i);
26  // Clear strobe bit, or MSX joysticks will stay silent.
27  ports[i]->write(0xFB, time);
28  }
29  reset(time);
30 }
31 
32 void ColecoJoystickIO::reset(EmuTime::param /*time*/)
33 {
34  joyMode = 0;
35 }
36 
37 byte ColecoJoystickIO::peekIO(word port, EmuTime::param time) const
38 {
39  const int joyPort = (port >> 1) & 1;
40  const byte joyStatus = ports[joyPort]->read(time);
41  const byte* keys = keyboard.getKeys();
42 
43  byte value;
44  if (joyMode == 0) {
45  // Combine keypad rows, convert to high-active and drop unused bits.
46  // Note: The keypad can only return one button press, but I don't know
47  // what happens if you press two buttons at once.
48  unsigned keypadStatus = ~(
49  keys[joyPort * 2 + 2] | (keys[joyPort * 2 + 3] << 8)
50  ) & 0xFFF;
51  constexpr byte keyEnc[] = {
52  0xF, 0xA, 0xD, 0x7, 0xC, 0x2, 0x3, 0xE, 0x5, 0x1, 0xB, 0x9, 0x6
53  };
54  value = keyEnc[Math::findFirstSet(keypadStatus)]
55  | 0x30 // not connected
56  | ((joyStatus << 1) & (keys[joyPort] >> 1) & 0x40); // trigger B
57  } else {
58  // Map MSX joystick direction bits to Coleco bits.
59  value =
60  ( joyStatus & 0x01) // up
61  | ((joyStatus >> 2) & 0x02) // right
62  | ((joyStatus << 1) & 0x04) // down
63  | ((joyStatus << 1) & 0x08) // left
64  | 0x30 // not connected
65  | ((joyStatus << 2) & 0x40) // trigger A
66  ;
67  // Note: ColEm puts 0 in bit 7.
68  // I don't know why this is different from bit 4 and 5.
69  // Combine with row 0/1 of keyboard matrix.
70  value &= keys[joyPort] | ~0x4F;
71  }
72  return value;
73 }
74 
75 byte ColecoJoystickIO::readIO(word port, EmuTime::param time)
76 {
77  return peekIO(port, time);
78 }
79 
80 void ColecoJoystickIO::writeIO(word port, byte /*value*/, EmuTime::param /*time*/)
81 {
82  joyMode = (port >> 6) & 1;
83 }
84 
85 template<typename Archive>
86 void ColecoJoystickIO::serialize(Archive& ar, unsigned version)
87 {
88  ar.template serializeBase<MSXDevice>(*this);
89  ar.serialize("joyMode", joyMode);
90  if (ar.versionAtLeast(version, 2)) {
91  ar.serialize("keyboard", keyboard);
92  }
93 }
96 
97 } // namespace openmsx
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:32
Math::findFirstSet
unsigned findFirstSet(unsigned x)
Find the least significant bit that is set.
Definition: Math.hh:256
serialize.hh
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
openmsx::MSXMotherBoard::getJoystickPort
JoystickPortIf & getJoystickPort(unsigned port)
Definition: MSXMotherBoard.cc:426
JoystickPort.hh
openmsx::ColecoJoystickIO::ColecoJoystickIO
ColecoJoystickIO(const DeviceConfig &config)
Definition: ColecoJoystickIO.cc:10
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
Reactor.hh
openmsx::MSXDevice::getCurrentTime
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:60
openmsx::ColecoJoystickIO::serialize
void serialize(Archive &ar, unsigned version)
Definition: ColecoJoystickIO.cc:86
openmsx::ColecoJoystickIO::readIO
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: ColecoJoystickIO.cc:75
openmsx::ColecoJoystickIO::writeIO
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: ColecoJoystickIO.cc:80
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::MSXDevice::getMotherBoard
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:75
openmsx::Keyboard::getKeys
const byte * getKeys() const
Returns a pointer to the current KeyBoard matrix.
Definition: Keyboard.cc:233
openmsx::Keyboard
Definition: Keyboard.hh:37
openmsx::ColecoJoystickIO::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: ColecoJoystickIO.cc:32
ColecoJoystickIO.hh
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::JoystickPortIf::write
virtual void write(byte value, EmuTime::param time)=0
openmsx::ColecoJoystickIO
Definition: ColecoJoystickIO.hh:13
openmsx::JoystickPortIf::read
virtual byte read(EmuTime::param time)=0
Math.hh
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
MSXMotherBoard.hh
openmsx::ColecoJoystickIO::peekIO
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: ColecoJoystickIO.cc:37