OXYGENHUB
◆ main openmsx / src / input / ColecoJoystickIO.cc
2.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "ColecoJoystickIO.hh"
2
3
#include "JoystickPort.hh"
4
#include "MSXMotherBoard.hh"
5
#include "Reactor.hh"
6
#include "serialize.hh"
7
8
#include "Math.hh"
9
#include "enumerate.hh"
10
11
#include <array>
12
13
namespace openmsx {
14
15
ColecoJoystickIO::ColecoJoystickIO(const DeviceConfig& config)
16
	: MSXDevice(config)
17
	, keyboard(
18
		config.getMotherBoard(),
19
		config.getMotherBoard().getScheduler(),
20
		config.getMotherBoard().getCommandController(),
21
		config.getMotherBoard().getReactor().getEventDistributor(),
22
		config.getMotherBoard().getMSXEventDistributor(),
23
		config.getMotherBoard().getStateChangeDistributor(),
24
		Keyboard::Matrix::CVJOY,
25
		config)
26
{
27
	MSXMotherBoard& motherBoard = getMotherBoard();
28
	auto time = getCurrentTime();
29
	for (auto [i, port] : enumerate(ports)) {
30
		port = &motherBoard.getJoystickPort(unsigned(i));
31
		// Clear strobe bit, or MSX joysticks will stay silent.
32
		port->write(0xFB, time);
33
	}
34
	reset(time);
35
}
36
37
void ColecoJoystickIO::reset(EmuTime /*time*/)
38
{
39
	joyMode = 0;
40
}
41
42
byte ColecoJoystickIO::peekIO(uint16_t port, EmuTime time) const
43
{
44
	const int joyPort = (port >> 1) & 1;
45
	const byte joyStatus = ports[joyPort]->read(time);
46
	auto keys = keyboard.getKeys();
47
48
	if (joyMode == 0) {
49
		// Combine keypad rows, convert to high-active and drop unused bits.
50
		// Note: The keypad can only return one button press, but I don't know
51
		//       what happens if you press two buttons at once.
52
		unsigned keypadStatus = ~(
53
			keys[joyPort * 2 + 2] | (keys[joyPort * 2 + 3] << 8)
54
			) & 0xFFF;
55
		static constexpr std::array<byte, 13> keyEnc = {
56
			0xF, 0xA, 0xD, 0x7, 0xC, 0x2, 0x3, 0xE, 0x5, 0x1, 0xB, 0x9, 0x6
57
		};
58
		return keyEnc[Math::findFirstSet(keypadStatus)]
59
		     | 0x30 // not connected
60
		     | ((joyStatus << 1) & (keys[joyPort] >> 1) & 0x40); // trigger B
61
	} else {
62
		// Map MSX joystick direction bits to Coleco bits.
63
		byte value =
64
			  ( joyStatus       & 0x01) // up
65
			| ((joyStatus >> 2) & 0x02) // right
66
			| ((joyStatus << 1) & 0x04) // down
67
			| ((joyStatus << 1) & 0x08) // left
68
			| 0x30 // not connected
69
			| ((joyStatus << 2) & 0x40) // trigger A
70
			;
71
			// Note: ColEm puts 0 in bit 7.
72
			//       I don't know why this is different from bit 4 and 5.
73
		// Combine with row 0/1 of keyboard matrix.
74
		return value & (keys[joyPort] | ~0x4F);
75
	}
76
}
77
78
byte ColecoJoystickIO::readIO(uint16_t port, EmuTime time)
79
{
80
	return peekIO(port, time);
81
}
82
83
void ColecoJoystickIO::writeIO(uint16_t port, byte /*value*/, EmuTime /*time*/)
84
{
85
	joyMode = (port >> 6) & 1;
86
}
87
88
template<typename Archive>
89
void ColecoJoystickIO::serialize(Archive& ar, unsigned version)
90
{
91
	ar.template serializeBase<MSXDevice>(*this);
92
	ar.serialize("joyMode", joyMode);
93
	if (ar.versionAtLeast(version, 2)) {
94
		ar.serialize("keyboard", keyboard);
95
	}
96
}
97
INSTANTIATE_SERIALIZE_METHODS(ColecoJoystickIO);
98
REGISTER_MSXDEVICE(ColecoJoystickIO, "ColecoJoystick");
99
100
} // namespace openmsx