OXYGENHUB
◆ main openmsx / src / MSXPrinterPort.cc
3.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "MSXPrinterPort.hh"
2
3
#include "DummyPrinterPortDevice.hh"
4
#include "serialize.hh"
5
6
#include "checked_cast.hh"
7
#include "narrow.hh"
8
#include "outer.hh"
9
#include "unreachable.hh"
10
11
#include <cstdint>
12
#include <memory>
13
14
namespace openmsx {
15
16
MSXPrinterPort::MSXPrinterPort(const DeviceConfig& config)
17
	: MSXDevice(config)
18
	, Connector(MSXDevice::getPluggingController(), "printerport",
19
	            std::make_unique<DummyPrinterPortDevice>())
20
	, debuggable(getMotherBoard(), MSXDevice::getName())
21
        , writePortMask(config.getChildDataAsBool("bidirectional", false) ? 0x03 : 0x01)
22
        , readPortMask(config.getChildDataAsBool("status_readable_on_all_ports", false) ? 0 : writePortMask)
23
	, unusedBits(uint8_t(config.getChildDataAsInt("unused_bits", 0xFF))) // TODO: some machines use the port number as unused bits (e.g. lintweaker's Sanyo PHC-23)
24
{
25
	reset(getCurrentTime());
26
}
27
28
void MSXPrinterPort::reset(EmuTime time)
29
{
30
	writeData(0, time);    // TODO check this
31
	setStrobe(true, time); // TODO check this
32
}
33
34
uint8_t MSXPrinterPort::readIO(uint16_t port, EmuTime time)
35
{
36
	return peekIO(port, time);
37
}
38
39
uint8_t MSXPrinterPort::peekIO(uint16_t port, EmuTime time) const
40
{
41
	bool showStatus = (port & readPortMask) == 0;
42
	if (!showStatus) return 0xFF;
43
	// bit 1 = status / other bits depend on something unknown, specified
44
	// in the XML file
45
	return getPluggedPrintDev().getStatus(time)
46
		       ? (unusedBits | 0b10) : (unusedBits & ~0b10);
47
}
48
49
void MSXPrinterPort::writeIO(uint16_t port, uint8_t value, EmuTime time)
50
{
51
	switch (port & writePortMask) {
52
	case 0:
53
		setStrobe(value & 1, time); // bit 0 = strobe
54
		break;
55
	case 1:
56
		writeData(value, time);
57
		break;
58
	case 2: // nothing here
59
		break;
60
	case 3: // 0x93 PDIR (BiDi) is not implemented.
61
		break;
62
	default:
63
		UNREACHABLE;
64
	}
65
}
66
67
void MSXPrinterPort::setStrobe(bool newStrobe, EmuTime time)
68
{
69
	if (newStrobe != strobe) {
70
		strobe = newStrobe;
71
		getPluggedPrintDev().setStrobe(strobe, time);
72
	}
73
}
74
void MSXPrinterPort::writeData(uint8_t newData, EmuTime time)
75
{
76
	if (newData != data) {
77
		data = newData;
78
		getPluggedPrintDev().writeData(data, time);
79
	}
80
}
81
82
zstring_view MSXPrinterPort::getDescription() const
83
{
84
	return "MSX Printer port";
85
}
86
87
zstring_view MSXPrinterPort::getClass() const
88
{
89
	return "Printer Port";
90
}
91
92
void MSXPrinterPort::plug(Pluggable& dev, EmuTime time)
93
{
94
	Connector::plug(dev, time);
95
	getPluggedPrintDev().writeData(data, time);
96
	getPluggedPrintDev().setStrobe(strobe, time);
97
}
98
99
PrinterPortDevice& MSXPrinterPort::getPluggedPrintDev() const
100
{
101
	return *checked_cast<PrinterPortDevice*>(&getPlugged());
102
}
103
104
105
MSXPrinterPort::Debuggable::Debuggable(MSXMotherBoard& motherBoard_, const std::string& name_)
106
	: SimpleDebuggable(motherBoard_, name_, "Printer Port", 2)
107
{
108
}
109
110
uint8_t MSXPrinterPort::Debuggable::read(unsigned address)
111
{
112
	const auto& pPort = OUTER(MSXPrinterPort, debuggable);
113
	return (address == 0) ? pPort.strobe : pPort.data;
114
}
115
116
void MSXPrinterPort::Debuggable::write(unsigned address, uint8_t value)
117
{
118
	auto& pPort = OUTER(MSXPrinterPort, debuggable);
119
	pPort.writeIO(narrow<uint16_t>(address), value, pPort.getCurrentTime());
120
}
121
122
123
template<typename Archive>
124
void MSXPrinterPort::serialize(Archive& ar, unsigned /*version*/)
125
{
126
	ar.template serializeBase<MSXDevice>(*this);
127
	ar.template serializeBase<Connector>(*this);
128
	ar.serialize("strobe", strobe,
129
	             "data",   data);
130
	// TODO force writing data to port??
131
}
132
INSTANTIATE_SERIALIZE_METHODS(MSXPrinterPort);
133
REGISTER_MSXDEVICE(MSXPrinterPort, "PrinterPort");
134
135
} // namespace openmsx