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