OXYGENHUB
◆ main openmsx / src / sound / MSXMusic.cc
4.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "MSXMusic.hh"
2
3
#include "CacheLine.hh"
4
#include "MSXException.hh"
5
#include "serialize.hh"
6
7
#include <bit>
8
9
namespace openmsx {
10
11
// class MSXMusicBase
12
13
MSXMusicBase::MSXMusicBase(DeviceConfig& config)
14
	: MSXDevice(config)
15
	, rom(getName() + " ROM", "rom", config)
16
	, ym2413(getName(), config)
17
{
18
	if (!std::has_single_bit(rom.size())) {
19
		throw MSXException("MSX-Music ROM-size must be a non-zero power of two");
20
	}
21
	MSXMusicBase::reset(getCurrentTime());
22
}
23
24
void MSXMusicBase::reset(EmuTime time)
25
{
26
	ym2413.reset(time);
27
}
28
29
void MSXMusicBase::writeIO(uint16_t port, byte value, EmuTime time)
30
{
31
	writePort(port & 1, value, time);
32
}
33
34
void MSXMusicBase::writePort(bool port, byte value, EmuTime time)
35
{
36
	ym2413.writePort(port, value, time);
37
}
38
39
byte MSXMusicBase::peekMem(uint16_t address, EmuTime /*time*/) const
40
{
41
	return *MSXMusicBase::getReadCacheLine(address);
42
}
43
44
byte MSXMusicBase::readMem(uint16_t address, EmuTime time)
45
{
46
	return peekMem(address, time);
47
}
48
49
const byte* MSXMusicBase::getReadCacheLine(uint16_t start) const
50
{
51
	return &rom[start & (rom.size() - 1)];
52
}
53
54
// version 1: initial version
55
// version 2: refactored YM2413 class structure
56
// version 3: removed 'registerLatch' (moved to YM2413 cores)
57
template<typename Archive>
58
void MSXMusicBase::serialize(Archive& ar, unsigned version)
59
{
60
	ar.template serializeBase<MSXDevice>(*this);
61
62
	if (ar.versionAtLeast(version, 2)) {
63
		ar.serialize("ym2413", ym2413);
64
	} else {
65
		// In older versions, the 'ym2413' level was missing, delegate
66
		// directly to YM2413 without emitting the 'ym2413' tag.
67
		ym2413.serialize(ar, version);
68
	}
69
}
70
INSTANTIATE_SERIALIZE_METHODS(MSXMusicBase);
71
72
73
74
// class MSXMusic
75
76
MSXMusic::MSXMusic(DeviceConfig& config)
77
	: MSXMusicBase(config)
78
{
79
}
80
81
template<typename Archive>
82
void MSXMusic::serialize(Archive& ar, unsigned version)
83
{
84
	ar.template serializeInlinedBase<MSXMusicBase>(*this, version);
85
}
86
INSTANTIATE_SERIALIZE_METHODS(MSXMusic);
87
REGISTER_MSXDEVICE(MSXMusic, "MSX-Music");
88
89
90
91
// class MSXMusicWX
92
93
// Thanks to NYYRIKKI for figuring this out:
94
//  - writes to 0x7ff0-0x7fff set a control register (mirrored 16x)
95
//  - writes to any other memory region have no effect
96
//  - bit 0 of this control register can be used to disable reading the ROM
97
//    (0=enable, 1=disabled), other bits seem to have no effect
98
//  - reading from 0x7ff0-0x7fff return the last written value OR 0xfc, IOW the
99
//    lower two bits are the last written value, higher bits always read 1
100
//  - reading from 0x4000-0x7fef returns the content of the ROM if the ROM is
101
//    enabled (bit 0 of the control register = 0), when the ROM is disabled
102
//    reads return 0xff
103
//  - reading any other memory location returns 0xff
104
105
MSXMusicWX::MSXMusicWX(DeviceConfig& config)
106
	: MSXMusicBase(config)
107
{
108
	reset(getCurrentTime());
109
}
110
111
void MSXMusicWX::reset(EmuTime time)
112
{
113
	MSXMusicBase::reset(time);
114
	control = 0;
115
}
116
117
byte MSXMusicWX::peekMem(uint16_t address, EmuTime time) const
118
{
119
	if ((0x7FF0 <= address) && (address < 0x8000)) {
120
		return control | 0xFC;
121
	} else if ((control & 1) == 0) {
122
		return MSXMusicBase::peekMem(address, time);
123
	} else {
124
		return 0xFF;
125
	}
126
}
127
128
byte MSXMusicWX::readMem(uint16_t address, EmuTime time)
129
{
130
	return peekMem(address, time);
131
}
132
133
const byte* MSXMusicWX::getReadCacheLine(uint16_t start) const
134
{
135
	if ((0x7FF0 & CacheLine::HIGH) == start) {
136
		return nullptr;
137
	} else if ((control & 1) == 0) {
138
		return MSXMusicBase::getReadCacheLine(start);
139
	} else {
140
		return unmappedRead.data();
141
	}
142
}
143
144
void MSXMusicWX::writeMem(uint16_t address, byte value, EmuTime /*time*/)
145
{
146
	if ((0x7FF0 <= address) && (address < 0x8000)) {
147
		control = value & 3;
148
		invalidateDeviceRCache();
149
	}
150
}
151
152
byte* MSXMusicWX::getWriteCacheLine(uint16_t start)
153
{
154
	if ((0x7FF0 & CacheLine::HIGH) == start) {
155
		return nullptr;
156
	} else {
157
		return unmappedWrite.data();
158
	}
159
}
160
161
template<typename Archive>
162
void MSXMusicWX::serialize(Archive& ar, unsigned version)
163
{
164
	ar.template serializeInlinedBase<MSXMusicBase>(*this, version);
165
	ar.serialize("control", control);
166
}
167
INSTANTIATE_SERIALIZE_METHODS(MSXMusicWX);
168
REGISTER_MSXDEVICE(MSXMusicWX, "MSX-Music-WX");
169
170
} // namespace openmsx