OXYGENHUB
◆ main openmsx / src / input / NinjaTap.cc
2.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "NinjaTap.hh"
2
3
#include "JoystickPort.hh"
4
5
#include "enumerate.hh"
6
#include "serialize.hh"
7
8
#include <algorithm>
9
10
// See this (long) MRC thread for a detailed discussion on NinjaTap, including
11
// an electric schema.
12
//   https://www.msx.org/forum/msx-talk/hardware/ninja-tap
13
14
namespace openmsx {
15
16
NinjaTap::NinjaTap(PluggingController& pluggingController_, std::string name_)
17
	: JoyTap(pluggingController_, std::move(name_))
18
{
19
	std::ranges::fill(buf, 0xFF);
20
}
21
22
zstring_view NinjaTap::getDescription() const
23
{
24
	return "MSX Ninja Tap device";
25
}
26
27
28
void NinjaTap::plugHelper(Connector& /*connector*/, EmuTime time)
29
{
30
	createPorts("Ninja Tap port", time);
31
}
32
33
uint8_t NinjaTap::read(EmuTime /*time*/)
34
{
35
	return status;
36
}
37
38
void NinjaTap::write(uint8_t value, EmuTime time)
39
{
40
	// bit 0 -> pin 6
41
	// bit 1 -> pin 7
42
	// bit 2 -> pin 8
43
	if (value & 2) {
44
		// pin7 = 1 :  read mode
45
		if (!(value & 1) && (previous & 1)) {
46
			// pin 6 1->0 :  query joysticks
47
			// TODO does output change?
48
			for (auto [i, slave] : enumerate(slaves)) {
49
				uint8_t t = slave->read(time);
50
				buf[i] = uint8_t(((t & 0x0F) << 4) |
51
				                 ((t & 0x30) >> 4) |
52
				                 0x0C);
53
			}
54
		}
55
		if (!(value & 4) && (previous & 4)) {
56
			// pin 8 1->0 :  shift values
57
			// TODO what about b4 and b5?
58
			uint8_t t = 0;
59
			for (auto [i, b] : enumerate(buf)) {
60
				if (b & 1) t |= (1 << i);
61
				b >>= 1;
62
			}
63
			status = (status & ~0x0F) | t;
64
		}
65
	}
66
67
	// pin7 (b5) is always the inverse of pin8
68
	// See Danjovic's post from 08-10-2022, 06:58
69
	//    https://www.msx.org/forum/msx-talk/hardware/ninja-tap?page=7
70
	if (value & 4) {
71
		status &= ~0x20;
72
	} else {
73
		status |= 0x20;
74
	}
75
76
	previous = value;
77
}
78
79
80
template<typename Archive>
81
void NinjaTap::serialize(Archive& ar, unsigned /*version*/)
82
{
83
	ar.template serializeBase<JoyTap>(*this);
84
	ar.serialize("status",   status,
85
	             "previous", previous,
86
	             "buf",      buf);
87
}
88
INSTANTIATE_SERIALIZE_METHODS(NinjaTap);
89
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, NinjaTap, "NinjaTap");
90
91
} // namespace openmsx