openMSX
MSXMoonSound.cc
Go to the documentation of this file.
1#include "MSXMoonSound.hh"
2
3#include "serialize.hh"
4
5#include "one_of.hh"
6
7#include <type_traits>
8
9namespace openmsx {
10
11static 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
30static 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
91 : MSXDevice(config)
92 , ymf278b(getName(), getRamSize(config), config, setupMemPtrs, getCurrentTime())
93{
94}
95
96void MSXMoonSound::powerUp(EmuTime::param time)
97{
98 ymf278b.powerUp(time);
99}
100
101void MSXMoonSound::reset(EmuTime::param time)
102{
103 ymf278b.reset(time);
104}
105
106byte MSXMoonSound::readIO(word port, EmuTime::param time)
107{
108 return ymf278b.readIO(port, time);
109}
110
111byte MSXMoonSound::peekIO(word port, EmuTime::param time) const
112{
113 return ymf278b.peekIO(port, time);
114}
115
116void MSXMoonSound::writeIO(word port, byte value, EmuTime::param time)
117{
118 ymf278b.writeIO(port, value, time);
119}
120
121// version 1: initial version
122// version 2: added alreadyReadID
123// version 3: moved loadTime and busyTime from YMF278 to here
124// removed alreadyReadID
125// version 4: moved (most) state to YMF278B
126template<typename Archive>
127void MSXMoonSound::serialize(Archive& ar, unsigned version)
128{
129 ar.template serializeBase<MSXDevice>(*this);
130
131 if (ar.versionAtLeast(version, 4)) {
132 ar.serialize("ymf278b", ymf278b);
133 } else {
134 assert(Archive::IS_LOADER);
135 if constexpr (std::is_same_v<Archive, XmlInputArchive>) {
136 ymf278b.serialize_bw_compat(
137 static_cast<XmlInputArchive&>(ar), version, getCurrentTime());
138 } else {
139 assert(false);
140 }
141 }
142}
145
146} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
EmuTime::param getCurrentTime() const
Definition MSXDevice.cc:125
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
MSXMoonSound(const DeviceConfig &config)
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
void serialize(Archive &ar, unsigned version)
void reset(EmuTime::param time) override
This method is called on reset.
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
void writeIO(word port, byte value, EmuTime::param time)
Definition YMF278B.cc:138
void powerUp(EmuTime::param time)
Definition YMF278B.cc:51
void serialize_bw_compat(XmlInputArchive &ar, unsigned version, EmuTime::param time)
Definition YMF278B.cc:224
byte readIO(word port, EmuTime::param time)
Definition YMF278B.cc:69
byte peekIO(word port, EmuTime::param time) const
Definition YMF278B.cc:111
void reset(EmuTime::param time)
Definition YMF278B.cc:57
static constexpr auto k128
Definition YMF278.hh:27
optional_fixed_span< const uint8_t, k128 > Block128
Definition YMF278.hh:28
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)
Definition xrange.hh:132