openMSX
MSXMapperIO.cc
Go to the documentation of this file.
1#include "MSXMapperIO.hh"
2#include "MSXMotherBoard.hh"
3#include "HardwareConfig.hh"
4#include "XMLElement.hh"
5#include "MSXException.hh"
6#include "StringOp.hh"
7#include "enumerate.hh"
8#include "outer.hh"
9#include "serialize.hh"
10#include "stl.hh"
11#include <algorithm>
12
13namespace openmsx {
14
15[[nodiscard]] static byte calcReadBackMask(MSXMotherBoard& motherBoard)
16{
17 std::string_view type = motherBoard.getMachineConfig()->getConfig().getChildData(
18 "MapperReadBackBits", "largest");
19 if (type == "largest") {
20 return 0xff; // all bits can be read
21 }
22 auto bits = StringOp::stringTo<int>(type);
23 if (!bits) {
24 throw FatalError("Unknown mapper type: \"", type, "\".");
25 }
26 if (*bits < 0 || *bits > 8) {
27 throw FatalError("MapperReadBackBits out of range: \"", type, "\".");
28 }
29 return ~(unsigned(-1) << *bits);
30}
31
33 : MSXDevice(config)
34 , debuggable(getMotherBoard(), getName())
35 , mask(calcReadBackMask(getMotherBoard()))
36{
37 reset(EmuTime::dummy());
38}
39
40void MSXMapperIO::setMode(Mode mode_, byte mask_, byte baseValue_)
41{
42 mode = mode_;
43 mask = mask_;
44 baseValue = baseValue_;
45}
46
48{
49 mappers.push_back(mapper);
50}
51
53{
54 mappers.erase(rfind_unguarded(mappers, mapper));
55}
56
57byte MSXMapperIO::readIO(word port, EmuTime::param time)
58{
59 byte value = [&] {
60 if (mode == Mode::EXTERNAL) {
61 byte result = 0xFF;
62 for (auto* mapper : mappers) {
63 result &= mapper->readIO(port, time);
64 }
65 return result;
66 } else {
67 return registers[port & 3];
68 }
69 }();
70 return (value & mask) | (baseValue & ~mask);
71}
72
73byte MSXMapperIO::peekIO(word port, EmuTime::param time) const
74{
75 byte value = [&] {
76 if (mode == Mode::EXTERNAL) {
77 byte result = 0xFF;
78 for (auto* mapper : mappers) {
79 result &= mapper->peekIO(port, time);
80 }
81 return result;
82 } else {
83 return registers[port & 3];
84 }
85 }();
86 return (value & mask) | (baseValue & ~mask);
87}
88
89void MSXMapperIO::writeIO(word port, byte value, EmuTime::param time)
90{
91 registers[port & 3] = value;
92
93 // Note: the mappers are responsible for invalidating/filling the CPU
94 // cache-lines.
95 for (auto* mapper : mappers) {
96 mapper->writeIO(port, value, time);
97 }
98}
99
100
101// SimpleDebuggable
102// This debuggable is here for backwards compatibility. For more accurate
103// results, use the debuggable belonging to a specific mapper.
104
105MSXMapperIO::Debuggable::Debuggable(MSXMotherBoard& motherBoard_,
106 const std::string& name_)
107 : SimpleDebuggable(motherBoard_, name_, "Memory mapper registers", 4)
108{
109}
110
111byte MSXMapperIO::Debuggable::read(unsigned address)
112{
113 // return the last written value, with full 8-bit precision.
114 auto& mapperIO = OUTER(MSXMapperIO, debuggable);
115 return mapperIO.registers[address & 3];
116}
117
118void MSXMapperIO::Debuggable::write(unsigned address, byte value,
119 EmuTime::param time)
120{
121 auto& mapperIO = OUTER(MSXMapperIO, debuggable);
122 mapperIO.writeIO(address, value, time);
123}
124
125
126template<typename Archive>
127void MSXMapperIO::serialize(Archive& ar, unsigned version)
128{
129 if (ar.versionBelow(version, 2)) {
130 // In version 1 we stored the mapper state in MSXMapperIO instead of
131 // in the individual mappers, so distribute the state to them.
132 assert(Archive::IS_LOADER);
133 ar.serialize("registers", registers);
134 for (auto [page, reg] : enumerate(registers)) {
135 writeIO(word(page), reg, EmuTime::dummy());
136 }
137 }
138 if (ar.versionAtLeast(version, 3)) {
139 // In version 3 we store the mapper state BOTH here and in the
140 // individual mappers. The reason for this is:
141 // - There are MSX machines with a S1985 but without a memory
142 // mapper. To support those we need to store the state here.
143 // - In rare cases (e.g. musical memory mapper) the mapper state
144 // can be different for specific mappers.
145 ar.serialize("registers", registers);
146 }
147}
149
150} // namespace openmsx
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:34
virtual void reset(EmuTime::param time)
This method is called on reset.
Definition: MSXDevice.cc:355
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: MSXMapperIO.cc:73
void registerMapper(MSXMemoryMapperInterface *mapper)
Definition: MSXMapperIO.cc:47
MSXMapperIO(const DeviceConfig &config)
Definition: MSXMapperIO.cc:32
void serialize(Archive &ar, unsigned version)
Definition: MSXMapperIO.cc:127
void unregisterMapper(MSXMemoryMapperInterface *mapper)
Definition: MSXMapperIO.cc:52
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.
Definition: MSXMapperIO.cc:89
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: MSXMapperIO.cc:57
void setMode(Mode mode, byte mask, byte baseValue)
Definition: MSXMapperIO.cc:40
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:730
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define OUTER(type, member)
Definition: outer.hh:41
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition: stl.hh:100