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