OXYGENHUB
◆ main openmsx / src / DebugDevice.cc
3.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "DebugDevice.hh"
2
3
#include "Clock.hh"
4
#include "serialize.hh"
5
6
#include "FileOperations.hh"
7
8
#include "narrow.hh"
9
#include "strCat.hh"
10
11
#include <format>
12
#include <iostream>
13
14
namespace openmsx {
15
16
DebugDevice::DebugDevice(const DeviceConfig& config)
17
	: MSXDevice(config)
18
	, fileNameSetting(
19
		getCommandController(), tmpStrCat(getName(), " output"),
20
		"name of the file the debug-device outputs to",
21
		config.getChildData("filename", "stdout"))
22
{
23
	openOutput(fileNameSetting.getString());
24
	reset(EmuTime::dummy());
25
}
26
27
void DebugDevice::reset(EmuTime /*time*/)
28
{
29
	mode = Mode::OFF;
30
	modeParameter = 0;
31
}
32
33
void DebugDevice::writeIO(uint16_t port, byte value, EmuTime time)
34
{
35
	if (const auto& newName = fileNameSetting.getString();
36
	    newName != fileNameString) {
37
		openOutput(newName);
38
	}
39
40
	using enum Mode;
41
	switch (port & 0x01) {
42
	case 0:
43
		switch ((value & 0x30) >> 4) {
44
		case 0:
45
			mode = OFF;
46
			break;
47
		case 1:
48
			mode = SINGLEBYTE;
49
			modeParameter = value & 0x0F;
50
			break;
51
		case 2:
52
			mode = MULTIBYTE;
53
			modeParameter = value & 0x03;
54
			break;
55
		case 3:
56
			break;
57
		}
58
		if (!(value & 0x40)){
59
			(*outputStrm) << '\n' << std::flush;
60
		}
61
		break;
62
	case 1:
63
		switch (mode) {
64
		case OFF:
65
			break;
66
		case SINGLEBYTE:
67
			outputSingleByte(value, time);
68
			break;
69
		case MULTIBYTE:
70
			outputMultiByte(value);
71
			break;
72
		default:
73
			break;
74
		}
75
		break;
76
	}
77
}
78
79
void DebugDevice::outputSingleByte(byte value, EmuTime time)
80
{
81
	using enum DisplayType;
82
	if (modeParameter & 0x01) {
83
		displayByte(value, HEX);
84
	}
85
	if (modeParameter & 0x02) {
86
		displayByte(value, BIN);
87
	}
88
	if (modeParameter & 0x04) {
89
		displayByte(value, DEC);
90
	}
91
	if (modeParameter & 0x08) {
92
		(*outputStrm) << '\'';
93
		byte tmp = ((value >= ' ') && (value != 127)) ? value : '.';
94
		displayByte(tmp, ASC);
95
		(*outputStrm) << "' ";
96
	}
97
	Clock<3579545> zero(EmuTime::zero());
98
	(*outputStrm) << "emutime: " << zero.getTicksTill(time);
99
	if ((modeParameter & 0x08) && ((value < ' ') || (value == 127))) {
100
		displayByte(value, ASC); // do special effects
101
	}
102
	(*outputStrm) << '\n' << std::flush;
103
}
104
105
void DebugDevice::outputMultiByte(byte value)
106
{
107
	auto dispType = [&] {
108
		switch (modeParameter) {
109
			using enum DisplayType;
110
			case 0:  return HEX;
111
			case 1:  return BIN;
112
			case 2:  return DEC;
113
			case 3:
114
			default: return ASC;
115
		}
116
	}();
117
	displayByte(value, dispType);
118
}
119
120
void DebugDevice::displayByte(byte value, DisplayType type)
121
{
122
	switch (type) {
123
	using enum DisplayType;
124
	case HEX:
125
		(*outputStrm) << hex_string<2>(value) << "h " << std::flush;
126
		break;
127
	case BIN:
128
		(*outputStrm) << bin_string<8>(value) << "b " << std::flush;
129
		break;
130
	case DEC:
131
		(*outputStrm) << std::format("{:03d} ", value) << std::flush;
132
		break;
133
	case ASC:
134
		(*outputStrm).put(narrow_cast<char>(value));
135
		(*outputStrm) << std::flush;
136
		break;
137
	}
138
}
139
140
void DebugDevice::openOutput(std::string_view name)
141
{
142
	fileNameString = name;
143
	debugOut.close();
144
	if (name == "stdout") {
145
		outputStrm = &std::cout;
146
	} else if (name == "stderr") {
147
		outputStrm = &std::cerr;
148
	} else {
149
		auto realName = FileOperations::expandTilde(fileNameString);
150
		FileOperations::openOfStream(debugOut, realName, std::ios::app);
151
		outputStrm = &debugOut;
152
	}
153
}
154
155
static constexpr auto debugModeInfo = std::to_array<enum_string<DebugDevice::Mode>>({
156
	{ "OFF",        DebugDevice::Mode::OFF },
157
	{ "SINGLEBYTE", DebugDevice::Mode::SINGLEBYTE },
158
	{ "MULTIBYTE",  DebugDevice::Mode::MULTIBYTE },
159
	{ "ASCII",      DebugDevice::Mode::ASCII },
160
});
161
SERIALIZE_ENUM(DebugDevice::Mode, debugModeInfo);
162
163
template<typename Archive>
164
void DebugDevice::serialize(Archive& ar, unsigned /*version*/)
165
{
166
	ar.template serializeBase<MSXDevice>(*this);
167
	ar.serialize("mode",          mode,
168
	             "modeParameter", modeParameter);
169
}
170
INSTANTIATE_SERIALIZE_METHODS(DebugDevice);
171
REGISTER_MSXDEVICE(DebugDevice, "DebugDevice");
172
173
} // namespace openmsx