openMSX
RomManbow2.cc
Go to the documentation of this file.
1#include "RomManbow2.hh"
2#include "AY8910.hh"
4#include "SCC.hh"
5#include "MSXCPUInterface.hh"
6#include "one_of.hh"
7#include "ranges.hh"
8#include "serialize.hh"
9#include "unreachable.hh"
10#include "xrange.hh"
11#include <array>
12#include <cassert>
13#include <memory>
14
15namespace openmsx {
16
18
19// 512kB, only last 64kB writable
20static constexpr auto config1 = [] {
21 std::array<Info, 512 / 64> result = {};
22 ranges::fill(result, Info{64 * 1024, true}); // read-only
23 result[7].writeProtected = false;
24 return result;
25}();
26// 512kB, only 128kB writable
27static constexpr auto config2 = [] {
28 std::array<Info, 512 / 64> result = {};
29 ranges::fill(result, Info{64 * 1024, true}); // read-only
30 result[4].writeProtected = false;
31 result[5].writeProtected = false;
32 return result;
33}();
34// fully writeable, 512kB
35static constexpr auto config3 = [] {
36 std::array<Info, 512 / 64> result = {};
37 ranges::fill(result, Info{64 * 1024, false});
38 return result;
39}();
40// fully writeable, 2MB
41static constexpr auto config4 = [] {
42 std::array<Info, 2048 / 64> result = {};
43 ranges::fill(result, Info{64 * 1024, false});
44 return result;
45}();
46[[nodiscard]] static constexpr std::span<const Info> getSectorInfo(RomType type)
47{
48 switch (type) {
49 case ROM_MANBOW2:
50 case ROM_MANBOW2_2:
51 return config1;
53 return config2;
55 return config3;
57 return config4;
58 default:
60 return config1; // dummy
61 }
62}
63
65 RomType type)
66 : MSXRom(config, std::move(rom_))
67 , scc((type != ROM_RBSC_FLASH_KONAMI_SCC)
68 ? std::make_unique<SCC>(
69 getName() + " SCC", config, getCurrentTime())
70 : nullptr)
71 , psg((type == one_of(ROM_MANBOW2_2, ROM_HAMARAJANIGHT))
72 ? std::make_unique<AY8910>(
73 getName() + " PSG", DummyAY8910Periphery::instance(),
74 config, getCurrentTime())
75 : nullptr)
76 , flash(rom, getSectorInfo(type),
77 type == ROM_RBSC_FLASH_KONAMI_SCC ? 0x01AD : 0x01A4,
78 AmdFlash::Addressing::BITS_11, config)
79 , romBlockDebug(*this, bank, 0x4000, 0x8000, 13)
80{
82
83 if (psg) {
84 getCPUInterface().register_IO_Out(0x10, this);
85 getCPUInterface().register_IO_Out(0x11, this);
86 getCPUInterface().register_IO_In (0x12, this);
87 }
88}
89
91{
92 if (psg) {
95 getCPUInterface().unregister_IO_In (0x12, this);
96 }
97}
98
99void RomManbow2::powerUp(EmuTime::param time)
100{
101 if (scc) {
102 scc->powerUp(time);
103 }
104 reset(time);
105}
106
107void RomManbow2::reset(EmuTime::param time)
108{
109 for (auto i : xrange(4)) {
110 setRom(i, i);
111 }
112
113 sccEnabled = false;
114 if (scc) {
115 scc->reset(time);
116 }
117
118 if (psg) {
119 psgLatch = 0;
120 psg->reset(time);
121 }
122
123 flash.reset();
124}
125
126void RomManbow2::setRom(unsigned region, unsigned block)
127{
128 assert(region < 4);
129 unsigned nrBlocks = flash.getSize() / 0x2000;
130 bank[region] = block & (nrBlocks - 1);
131 invalidateDeviceRCache(0x4000 + region * 0x2000, 0x2000);
132}
133
134byte RomManbow2::peekMem(word address, EmuTime::param time) const
135{
136 if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
137 return scc->peekMem(address & 0xFF, time);
138 } else if ((0x4000 <= address) && (address < 0xC000)) {
139 unsigned page = (address - 0x4000) / 0x2000;
140 unsigned addr = (address & 0x1FFF) + 0x2000 * bank[page];
141 return flash.peek(addr);
142 } else {
143 return 0xFF;
144 }
145}
146
147byte RomManbow2::readMem(word address, EmuTime::param time)
148{
149 if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
150 return scc->readMem(address & 0xFF, time);
151 } else if ((0x4000 <= address) && (address < 0xC000)) {
152 unsigned page = (address - 0x4000) / 0x2000;
153 unsigned addr = (address & 0x1FFF) + 0x2000 * bank[page];
154 return flash.read(addr);
155 } else {
156 return 0xFF;
157 }
158}
159
160const byte* RomManbow2::getReadCacheLine(word address) const
161{
162 if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
163 return nullptr;
164 } else if ((0x4000 <= address) && (address < 0xC000)) {
165 unsigned page = (address - 0x4000) / 0x2000;
166 unsigned addr = (address & 0x1FFF) + 0x2000 * bank[page];
167 return flash.getReadCacheLine(addr);
168 } else {
169 return unmappedRead;
170 }
171}
172
173void RomManbow2::writeMem(word address, byte value, EmuTime::param time)
174{
175 if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
176 // write to SCC
177 scc->writeMem(address & 0xff, value, time);
178 // note: writes to SCC also go to flash
179 // thanks to 'enen' for testing this
180 }
181 if ((0x4000 <= address) && (address < 0xC000)) {
182 unsigned page = (address - 0x4000) / 0x2000;
183 unsigned addr = (address & 0x1FFF) + 0x2000 * bank[page];
184 flash.write(addr, value);
185
186 if (scc && ((address & 0xF800) == 0x9000)) {
187 // SCC enable/disable
188 sccEnabled = ((value & 0x3F) == 0x3F);
189 invalidateDeviceRCache(0x9800, 0x0800);
190 }
191 if ((address & 0x1800) == 0x1000) {
192 // page selection
193 setRom(page, value);
194 }
195 }
196}
197
199{
200 if ((0x4000 <= address) && (address < 0xC000)) {
201 return nullptr;
202 } else {
203 return unmappedWrite;
204 }
205}
206
207byte RomManbow2::readIO(word port, EmuTime::param time)
208{
209 assert((port & 0xFF) == 0x12); (void)port;
210 return psg->readRegister(psgLatch, time);
211}
212
213byte RomManbow2::peekIO(word port, EmuTime::param time) const
214{
215 assert((port & 0xFF) == 0x12); (void)port;
216 return psg->peekRegister(psgLatch, time);
217}
218
219void RomManbow2::writeIO(word port, byte value, EmuTime::param time)
220{
221 if ((port & 0xFF) == 0x10) {
222 psgLatch = value & 0x0F;
223 } else {
224 assert((port & 0xFF) == 0x11);
225 psg->writeRegister(psgLatch, value, time);
226 }
227}
228
229
230// version 1: initial version
231// version 2: added optional built-in PSG
232// version 3: made SCC optional (for ROM_RBSC_FLASH_KONAMI_SCC)
233template<typename Archive>
234void RomManbow2::serialize(Archive& ar, unsigned version)
235{
236 // skip MSXRom base class
237 ar.template serializeBase<MSXDevice>(*this);
238
239 if (scc) {
240 ar.serialize("scc", *scc,
241 "sccEnabled", sccEnabled);
242 }
243 if ((ar.versionAtLeast(version, 2)) && psg) {
244 ar.serialize("psg", *psg,
245 "psgLatch", psgLatch);
246 }
247 ar.serialize("flash", flash,
248 "bank", bank);
249}
252
253} // namespace openmsx
Definition: one_of.hh:7
This class implements the AY-3-8910 sound chip.
Definition: AY8910.hh:20
unsigned getSize() const
Definition: AmdFlash.hh:65
void write(unsigned address, byte value)
Definition: AmdFlash.cc:265
byte peek(unsigned address) const
Definition: AmdFlash.cc:212
byte read(unsigned address) const
Definition: AmdFlash.cc:248
const byte * getReadCacheLine(unsigned address) const
Definition: AmdFlash.cc:254
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
void unregister_IO_In(byte port, MSXDevice *device)
void unregister_IO_Out(byte port, MSXDevice *device)
void invalidateDeviceRCache()
Definition: MSXDevice.hh:210
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:301
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:126
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:302
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:134
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: RomManbow2.cc:213
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: RomManbow2.cc:160
~RomManbow2() override
Definition: RomManbow2.cc:90
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: RomManbow2.cc:219
RomManbow2(const DeviceConfig &config, Rom &&rom, RomType type)
Definition: RomManbow2.cc:64
void reset(EmuTime::param time) override
This method is called on reset.
Definition: RomManbow2.cc:107
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: RomManbow2.cc:134
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: RomManbow2.cc:99
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
Definition: RomManbow2.cc:173
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomManbow2.cc:147
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: RomManbow2.cc:207
void serialize(Archive &ar, unsigned version)
Definition: RomManbow2.cc:234
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: RomManbow2.cc:198
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:727
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
AmdFlash::SectorInfo Info
Definition: RomManbow2.cc:17
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
@ ROM_MANBOW2_2
Definition: RomTypes.hh:40
@ ROM_HAMARAJANIGHT
Definition: RomTypes.hh:26
@ ROM_MANBOW2
Definition: RomTypes.hh:39
@ ROM_MEGAFLASHROMSCC
Definition: RomTypes.hh:44
@ ROM_RBSC_FLASH_KONAMI_SCC
Definition: RomTypes.hh:41
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:256
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1009
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:133