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