OXYGENHUB
◆ main openmsx / src / sound / MSXMoonSound.cc
4.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "MSXMoonSound.hh"
2
3
#include "serialize.hh"
4
5
#include "one_of.hh"
6
7
#include <type_traits>
8
9
namespace openmsx {
10
11
static size_t getRamSize(const DeviceConfig& config)
12
{
13
	int ramSizeInKb = config.getChildDataAsInt("sampleram", 512);
14
	if (ramSizeInKb != one_of(
15
		   0,     //
16
		 128,     // 128kB
17
		 256,     // 128kB  128kB
18
		 512,     // 512kB
19
		 640,     // 512kB  128kB
20
		1024,     // 512kB  512kB
21
		2048)) {  // 512kB  512kB  512kB  512kB
22
		throw MSXException(
23
			"Wrong sample RAM size for MoonSound's YMF278. "
24
			"Got ", ramSizeInKb, ", but must be one of "
25
			"0, 128, 256, 512, 640, 1024 or 2048.");
26
	}
27
	return size_t(ramSizeInKb) * 1024; // kilo-bytes -> bytes
28
}
29
30
static void setupMemPtrs(bool mode0, std::span<const uint8_t> rom, std::span<const uint8_t> ram,
31
                         std::span<YMF278::Block128, 32> memPtrs)
32
{
33
	// /MCS0: connected to a 2MB ROM chip
34
	// For RAM there are multiple possibilities (but they all use /MCS6../MCS9)
35
	// * 128kB:
36
	//   1 SRAM chip of 128kB, chip enable (/CE) of this SRAM chip is connected to
37
	//   the 1Y0 output of a 74LS139 (2-to-4 decoder). The enable input of the
38
	//   74LS139 is connected to YMF278 pin /MCS6 and the 74LS139 1B:1A inputs are
39
	//   connected to YMF278 pins MA18:MA17. So the SRAM is selected when /MC6 is
40
	//   active and MA18:MA17 == 0:0.
41
	// * 256kB:
42
	//   2 SRAM chips of 128kB. First one connected as above. Second one has /CE
43
	//   connected to 74LS139 pin 1Y1. So SRAM2 is selected when /MSC6 is active
44
	//   and MA18:MA17 == 0:1.
45
	// * 512kB:
46
	//   1 SRAM chip of 512kB, /CE connected to /MCS6
47
	// * 640kB:
48
	//   1 SRAM chip of 512kB, /CE connected to /MCS6
49
	//   1 SRAM chip of 128kB, /CE connected to /MCS7.
50
	//     (This means SRAM2 is mirrored over a 512kB region)
51
	// * 1024kB:
52
	//   1 SRAM chip of 512kB, /CE connected to /MCS6
53
	//   1 SRAM chip of 512kB, /CE connected to /MCS7
54
	// * 2048kB:
55
	//   1 SRAM chip of 512kB, /CE connected to /MCS6
56
	//   1 SRAM chip of 512kB, /CE connected to /MCS7
57
	//   1 SRAM chip of 512kB, /CE connected to /MCS8
58
	//   1 SRAM chip of 512kB, /CE connected to /MCS9
59
	//   This configuration is not so easy to create on the v2.0 PCB. So it's
60
	//   very rare.
61
	// /MCS1../MCS5: unused
62
	static constexpr auto k128 = YMF278::k128;
63
64
	// first 2MB, ROM, both mode0 and mode1
65
	for (auto i : xrange(16)) {
66
		memPtrs[i] = subspan<k128>(rom, i * k128);
67
	}
68
69
	auto ramPart = [&](int i) {
70
		return (ram.size() >= (i + 1) * k128)
71
			? subspan<k128>(ram, i * k128)
72
			: YMF278::Block128{};
73
	};
74
	if (mode0) [[likely]] {
75
		// second 2MB, RAM, as much as if available, upto 2MB
76
		for (auto i : xrange(16)) {
77
			memPtrs[i + 16] = ramPart(i);
78
		}
79
	} else {
80
		// mode1, normally this shouldn't be used on MoonSound
81
		for (auto i : xrange(12)) {
82
			memPtrs[i + 16] = YMF278::Block128{};
83
		}
84
		for (auto i : xrange(4)) {
85
			memPtrs[i + 28] = ramPart(i);
86
		}
87
	}
88
}
89
90
MSXMoonSound::MSXMoonSound(DeviceConfig& config)
91
	: MSXDevice(config)
92
	, ymf278b(getName(), getRamSize(config), config, setupMemPtrs, getCurrentTime())
93
{
94
	powerUp(getCurrentTime());
95
}
96
97
void MSXMoonSound::powerUp(EmuTime time)
98
{
99
	ymf278b.powerUp(time);
100
}
101
102
void MSXMoonSound::reset(EmuTime time)
103
{
104
	ymf278b.reset(time);
105
}
106
107
byte MSXMoonSound::readIO(uint16_t port, EmuTime time)
108
{
109
	return ymf278b.readIO(port, time);
110
}
111
112
byte MSXMoonSound::peekIO(uint16_t port, EmuTime time) const
113
{
114
	return ymf278b.peekIO(port, time);
115
}
116
117
void MSXMoonSound::writeIO(uint16_t port, byte value, EmuTime time)
118
{
119
	ymf278b.writeIO(port, value, time);
120
}
121
122
// version 1: initial version
123
// version 2: added alreadyReadID
124
// version 3: moved loadTime and busyTime from YMF278 to here
125
//            removed alreadyReadID
126
// version 4: moved (most) state to YMF278B
127
template<typename Archive>
128
void MSXMoonSound::serialize(Archive& ar, unsigned version)
129
{
130
	ar.template serializeBase<MSXDevice>(*this);
131
132
	if (ar.versionAtLeast(version, 4)) {
133
		ar.serialize("ymf278b", ymf278b);
134
	} else {
135
		assert(Archive::IS_LOADER);
136
		if constexpr (std::is_same_v<Archive, XmlInputArchive>) {
137
			ymf278b.serialize_bw_compat(
138
				static_cast<XmlInputArchive&>(ar), version, getCurrentTime());
139
		} else {
140
			assert(false);
141
		}
142
	}
143
}
144
INSTANTIATE_SERIALIZE_METHODS(MSXMoonSound);
145
REGISTER_MSXDEVICE(MSXMoonSound, "MoonSound");
146
147
} // namespace openmsx