OXYGENHUB
◆ main openmsx / src / ProgrammableDevice.cc
2.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "ProgrammableDevice.hh"
2
3
#include "CommandController.hh"
4
#include "MSXCliComm.hh"
5
#include "MSXException.hh"
6
7
#include "narrow.hh"
8
#include "xrange.hh"
9
10
namespace openmsx {
11
12
[[nodiscard]] static IterableBitSet<256> parseAllPorts(const Setting& setting)
13
{
14
	Interpreter& interp = setting.getInterpreter();
15
	const auto& portList = setting.getValue();
16
	IterableBitSet<256> ports;
17
18
	for (auto n : xrange(portList.getListLength(interp))) {
19
		int tmp = portList.getListIndex(interp, n).getInt(interp);
20
		if ((tmp < 0) || (tmp > 255)) {
21
		        throw MSXException("outside range 0..255");
22
		}
23
		ports.set(narrow_cast<byte>(tmp));
24
	}
25
	return ports;
26
}
27
28
ProgrammableDevice::ProgrammableDevice(const DeviceConfig& config)
29
	: MSXDevice(config)
30
	, portListSetting(getCommandController(),
31
		tmpStrCat(getName(), " ports"),
32
		"List of ports that are added to the pool of I/O ports this extension scans for", "")
33
	, resetCallback(getCommandController(),
34
		tmpStrCat(getName(), " reset callback"),
35
		"Tcl proc to call when reset was detected, no parameters and return values are "
36
		"used", "", Setting::Save::NO)
37
	, inCallback(getCommandController(),
38
		tmpStrCat(getName(), " input callback"),
39
		"Defines a Tcl proc that receives a port number (byte) and returns a byte when "
40
		"the MSX is reading from a port of the device", "", Setting::Save::NO)
41
	, outCallback(getCommandController(),
42
		tmpStrCat(getName(), " output callback"),
43
		"Defines a Tcl proc that receives a port number (byte) and a byte when the "
44
		"MSX is writing to a port from the device", "", Setting::Save::NO)
45
{
46
	portListSetting.attach(*this);
47
	try {
48
		auto ports = parseAllPorts(portListSetting);
49
		inPorts  = ports;
50
		outPorts = ports;
51
	} catch (MSXException&) {
52
		// silently ignore error in settings.xml
53
		portListSetting.setString("");
54
	}
55
}
56
57
ProgrammableDevice::~ProgrammableDevice()
58
{
59
	portListSetting.detach(*this);
60
}
61
62
void ProgrammableDevice::update(const Setting& setting) noexcept
63
{
64
	try {
65
		auto ports = parseAllPorts(setting);
66
		unregisterPorts();
67
		inPorts  = ports;
68
		outPorts = ports;
69
		doRegisterPorts();
70
	} catch (MSXException& e) {
71
		getCliComm().printWarning(
72
			"Parse error in \"",
73
			portListSetting.getFullName(), "\": ", e.getMessage());
74
	}
75
}
76
77
void ProgrammableDevice::writeIO(uint16_t port, byte value, EmuTime /*time*/)
78
{
79
	outCallback.execute(port & 0xff, value);
80
}
81
82
byte ProgrammableDevice::readIO(uint16_t port, EmuTime /*time*/)
83
{
84
	try {
85
		auto obj = inCallback.execute(port & 0xff);
86
		int tmp = obj.getInt(getCommandController().getInterpreter());
87
		if ((tmp < 0) || (tmp > 255)) {
88
			throw MSXException("outside range 0..255");
89
		}
90
		return narrow_cast<byte>(tmp);
91
	} catch (MSXException& e) {
92
		getCliComm().printWarning(
93
			"Wrong result for callback function \"",
94
			inCallback.getSetting().getFullName(),
95
			"\": ", e.getMessage());
96
		return 0xff;
97
	}
98
}
99
100
void ProgrammableDevice::reset(EmuTime /*time*/)
101
{
102
	resetCallback.execute();
103
}
104
105
REGISTER_MSXDEVICE(ProgrammableDevice, "ProgrammableDevice");
106
107
} // namespace openmsx