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 "cstd.hh"
7 #include "one_of.hh"
8 #include "serialize.hh"
9 #include "unreachable.hh"
10 #include "xrange.hh"
11 #include <array>
12 #include <cassert>
13 #include <memory>
14 
15 namespace openmsx {
16 
18 
19 // 512kB, only last 64kB writable
20 static constexpr auto config1 = [] {
21  std::array<Info, 512 / 64> result = {};
22  cstd::fill(result, Info{64 * 1024, true}); // read-only
23  result[7].writeProtected = false;
24  return result;
25 }();
26 // 512kB, only 128kB writable
27 static constexpr auto config2 = [] {
28  std::array<Info, 512 / 64> result = {};
29  cstd::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
35 static constexpr auto config3 = [] {
36  std::array<Info, 512 / 64> result = {};
37  cstd::fill(result, Info{64 * 1024, false});
38  return result;
39 }();
40 // fully writeable, 2MB
41 static constexpr auto config4 = [] {
42  std::array<Info, 2048 / 64> result = {};
43  cstd::fill(result, Info{64 * 1024, false});
44  return result;
45 }();
46 [[nodiscard]] static constexpr span<const Info> getSectorInfo(RomType type)
47 {
48  switch (type) {
49  case ROM_MANBOW2:
50  case ROM_MANBOW2_2:
51  return config1;
52  case ROM_HAMARAJANIGHT:
53  return config2;
55  return config3;
57  return config4;
58  default:
60  return config1; // dummy
61  }
62 }
63 
64 RomManbow2::RomManbow2(const DeviceConfig& config, Rom&& rom_,
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) {
93  getCPUInterface().unregister_IO_Out(0x10, this);
94  getCPUInterface().unregister_IO_Out(0x11, this);
95  getCPUInterface().unregister_IO_In (0x12, this);
96  }
97 }
98 
99 void RomManbow2::powerUp(EmuTime::param time)
100 {
101  if (scc) {
102  scc->powerUp(time);
103  }
104  reset(time);
105 }
106 
107 void 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 
126 void 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 
134 byte 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 
147 byte 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 
160 const 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 
173 void 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 
207 byte RomManbow2::readIO(word port, EmuTime::param time)
208 {
209  assert((port & 0xFF) == 0x12); (void)port;
210  return psg->readRegister(psgLatch, time);
211 }
212 
213 byte RomManbow2::peekIO(word port, EmuTime::param time) const
214 {
215  assert((port & 0xFF) == 0x12); (void)port;
216  return psg->peekRegister(psgLatch, time);
217 }
218 
219 void 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)
233 template<typename Archive>
234 void 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:66
void write(unsigned address, byte value)
Definition: AmdFlash.cc:268
byte peek(unsigned address) const
Definition: AmdFlash.cc:215
byte read(unsigned address) const
Definition: AmdFlash.cc:251
const byte * getReadCacheLine(unsigned address) const
Definition: AmdFlash.cc:257
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:209
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:300
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:132
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:140
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
Definition: span.hh:126
constexpr void fill(ForwardIt first, ForwardIt last, const T &value)
Definition: cstd.hh:111
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:742
This file implemented 3 utility functions:
Definition: Autofire.cc:5
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
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:155