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