OXYGENHUB
◆ main openmsx / src / sound / MSXYamahaSFG.cc
4.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "MSXYamahaSFG.hh"
2
3
#include "CacheLine.hh"
4
#include "serialize.hh"
5
6
namespace openmsx {
7
8
static YM2151::Variant parseVariant(const DeviceConfig& config)
9
{
10
	auto variant = config.getChildData("variant", "YM2151");
11
	if (variant == "YM2151") return YM2151::Variant::YM2151;
12
	if (variant == "YM2164") return YM2151::Variant::YM2164;
13
	throw MSXException("Invalid variant '", variant, "', expected 'YM2151' or 'YM2164'.");
14
}
15
16
MSXYamahaSFG::MSXYamahaSFG(DeviceConfig& config)
17
	: MSXDevice(config)
18
	, rom(getName() + " ROM", "rom", config)
19
	, ym2151(getName(), "Yamaha SFG-01/05", config, getCurrentTime(), parseVariant(config))
20
	, ym2148(getName(), getMotherBoard())
21
{
22
	reset(getCurrentTime());
23
}
24
25
void MSXYamahaSFG::reset(EmuTime time)
26
{
27
	ym2151.reset(time);
28
	ym2148.reset();
29
	registerLatch = 0; // TODO check
30
	irqVector = 255; // TODO check
31
	irqVector2148 = 255; // TODO check
32
}
33
34
void MSXYamahaSFG::writeMem(uint16_t address, byte value, EmuTime time)
35
{
36
	uint16_t maskedAddress = address & 0x3FFF;
37
	switch (maskedAddress) {
38
	case 0x3FF0: // OPM ADDRESS REGISTER
39
		writeRegisterPort(value, time);
40
		break;
41
	case 0x3FF1: // OPM DATA REGISTER
42
		writeDataPort(value, time);
43
		break;
44
	case 0x3FF2: // Register for data latched to ST0 to ST7 output ports
45
		// TODO: keyboardLatch = value;
46
		//std::cerr << "TODO: keyboardLatch = " << (int)value << '\n';
47
		break;
48
	case 0x3FF3: // MIDI IRQ VECTOR ADDRESS REGISTER
49
		irqVector2148 = value;
50
		break;
51
	case 0x3FF4: // EXTERNAL IRQ VECTOR ADDRESS REGISTER
52
		// IRQ vector for YM2151 (+ default vector ???)
53
		irqVector = value;
54
		break;
55
	case 0x3FF5: // MIDI standard UART DATA WRITE BUFFER
56
		ym2148.writeData(value, time);
57
		break;
58
	case 0x3FF6: // MIDI standard UART COMMAND REGISTER
59
		ym2148.writeCommand(value);
60
		break;
61
	}
62
}
63
64
byte* MSXYamahaSFG::getWriteCacheLine(uint16_t start)
65
{
66
	if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FF0 & CacheLine::HIGH)) {
67
		return nullptr;
68
	}
69
	return unmappedWrite.data();
70
}
71
72
byte MSXYamahaSFG::readIRQVector()
73
{
74
	return ym2148.pendingIRQ() ? irqVector2148 : irqVector;
75
}
76
77
void MSXYamahaSFG::writeRegisterPort(byte value, EmuTime /*time*/)
78
{
79
	registerLatch = value;
80
}
81
82
void MSXYamahaSFG::writeDataPort(byte value, EmuTime time)
83
{
84
	ym2151.writeReg(registerLatch, value, time);
85
}
86
87
byte MSXYamahaSFG::readMem(uint16_t address, EmuTime time)
88
{
89
	uint16_t maskedAddress = address & 0x3FFF;
90
	if (maskedAddress < 0x3FF0 || maskedAddress >= 0x3FF8) {
91
		return peekMem(address, time);
92
	}
93
	switch (maskedAddress) {
94
	case 0x3FF0: // (not used, it seems)
95
	case 0x3FF1: // OPM STATUS REGISTER
96
	case 0x3FF2: // Data buffer for SD0 to SD7 input ports
97
		return peekMem(address, time);
98
	case 0x3FF5: // MIDI standard UART DATA READ BUFFER
99
		return ym2148.readData(time);
100
	case 0x3FF6: // MIDI standard UART STATUS REGISTER
101
		return ym2148.readStatus(time);
102
	}
103
	return 0xFF;
104
}
105
106
byte MSXYamahaSFG::peekMem(uint16_t address, EmuTime time) const
107
{
108
	uint16_t maskedAddress = address & 0x3FFF;
109
	if (maskedAddress < 0x3FF0 || maskedAddress >= 0x3FF8) {
110
		// size can also be 16kB for SFG-01 or 32kB for SFG-05
111
		return rom[address & (rom.size() - 1)];
112
	}
113
	switch (maskedAddress) {
114
	case 0x3FF0: // (not used, it seems)
115
		return 0xFF;
116
	case 0x3FF1: // OPM STATUS REGISTER
117
		return ym2151.readStatus();
118
	case 0x3FF2: // Data buffer for SD0 to SD7 input ports
119
		// TODO: return getKbdStatus();
120
		break;
121
	case 0x3FF5: // MIDI standard UART DATA READ BUFFER
122
		return ym2148.peekData(time);
123
	case 0x3FF6: // MIDI standard UART STATUS REGISTER
124
		return ym2148.peekStatus(time);
125
	}
126
	return 0xFF;
127
}
128
129
const byte* MSXYamahaSFG::getReadCacheLine(uint16_t start) const
130
{
131
	if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FF0 & CacheLine::HIGH)) {
132
		return nullptr;
133
	}
134
	return &rom[start & (rom.size() - 1)];
135
}
136
137
// version 1: initial version
138
// version 2: moved irqVector2148 from ym2148 to here
139
template<typename Archive>
140
void MSXYamahaSFG::serialize(Archive& ar, unsigned version)
141
{
142
	ar.serialize("YM2151",        ym2151,
143
	             "YM2148",        ym2148,
144
	             "registerLatch", registerLatch,
145
	             "irqVector",     irqVector);
146
	if (ar.versionAtLeast(version, 2)) {
147
		ar.serialize("irqVector2148", irqVector2148);
148
	} else {
149
		irqVector2148 = 255; // could be retrieved from the old ym2148
150
		                     // savestate data, but I didn't bother
151
	}
152
}
153
INSTANTIATE_SERIALIZE_METHODS(MSXYamahaSFG);
154
REGISTER_MSXDEVICE(MSXYamahaSFG, "YamahaSFG");
155
156
} // namespace openmsx