openMSX
MSXSCCPlusCart.cc
Go to the documentation of this file.
1 // Note: this device is actually called SCC-I. But this would take a lot of
2 // renaming, which isn't worth it right now. TODO rename this :)
3 
4 #include "MSXSCCPlusCart.hh"
5 #include "File.hh"
6 #include "FileContext.hh"
7 #include "FileException.hh"
8 #include "XMLElement.hh"
9 #include "CacheLine.hh"
10 #include "ranges.hh"
11 #include "serialize.hh"
12 
13 namespace openmsx {
14 
16  : MSXDevice(config)
17  , ram(config, getName() + " RAM", "SCC+ RAM", 0x20000)
18  , scc(getName(), config, getCurrentTime(), SCC::SCC_Compatible)
19  , romBlockDebug(*this, mapper, 0x4000, 0x8000, 13)
20 {
21  if (const XMLElement* fileElem = config.findChild("filename")) {
22  // read the rom file
23  const std::string& filename = fileElem->getData();
24  try {
25  File file(config.getFileContext().resolve(filename));
26  auto size = std::min<size_t>(file.getSize(), ram.getSize());
27  file.read(&ram[0], size);
28  } catch (FileException&) {
29  throw MSXException("Error reading file: ", filename);
30  }
31  }
32  std::string_view subtype = config.getChildData("subtype", "expanded");
33  if (subtype == "Snatcher") {
34  mapperMask = 0x0F;
35  lowRAM = true;
36  highRAM = false;
37  } else if (subtype == "SD-Snatcher") {
38  mapperMask = 0x0F;
39  lowRAM = false;
40  highRAM = true;
41  } else if (subtype == "mirrored") {
42  mapperMask = 0x07;
43  lowRAM = true;
44  highRAM = true;
45  } else {
46  // subtype "expanded", and all others
47  mapperMask = 0x0F;
48  lowRAM = true;
49  highRAM = true;
50  }
51 
52  // make valgrind happy
53  ranges::fill(isRamSegment, true);
54  ranges::fill(mapper, 0);
55 
57 }
58 
59 void MSXSCCPlusCart::powerUp(EmuTime::param time)
60 {
61  scc.powerUp(time);
62  reset(time);
63 }
64 
65 void MSXSCCPlusCart::reset(EmuTime::param time)
66 {
67  setModeRegister(0);
68  setMapper(0, 0);
69  setMapper(1, 1);
70  setMapper(2, 2);
71  setMapper(3, 3);
72  scc.reset(time);
73 }
74 
75 
76 byte MSXSCCPlusCart::readMem(word addr, EmuTime::param time)
77 {
78  if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
79  ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
80  return scc.readMem(addr & 0xFF, time);
81  } else {
82  return MSXSCCPlusCart::peekMem(addr, time);
83  }
84 }
85 
86 byte MSXSCCPlusCart::peekMem(word addr, EmuTime::param time) const
87 {
88  // modeRegister can not be read!
89  if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
90  ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
91  // SCC visible in 0x9800 - 0x9FFF
92  // SCC+ visible in 0xB800 - 0xBFFF
93  return scc.peekMem(addr & 0xFF, time);
94  } else if ((0x4000 <= addr) && (addr < 0xC000)) {
95  // SCC(+) enabled/disabled but not requested so memory stuff
96  return internalMemoryBank[(addr >> 13) - 2][addr & 0x1FFF];
97  } else {
98  // outside memory range
99  return 0xFF;
100  }
101 }
102 
103 const byte* MSXSCCPlusCart::getReadCacheLine(word start) const
104 {
105  if (((enable == EN_SCC) && (0x9800 <= start) && (start < 0xA000)) ||
106  ((enable == EN_SCCPLUS) && (0xB800 <= start) && (start < 0xC000))) {
107  // SCC visible in 0x9800 - 0x9FFF
108  // SCC+ visible in 0xB800 - 0xBFFF
109  return nullptr;
110  } else if ((0x4000 <= start) && (start < 0xC000)) {
111  // SCC(+) enabled/disabled but not requested so memory stuff
112  return &internalMemoryBank[(start >> 13) - 2][start & 0x1FFF];
113  } else {
114  // outside memory range
115  return unmappedRead;
116  }
117 }
118 
119 
120 void MSXSCCPlusCart::writeMem(word address, byte value, EmuTime::param time)
121 {
122  if ((address < 0x4000) || (0xC000 <= address)) {
123  // outside memory range
124  return;
125  }
126 
127  // Mode register is mapped upon 0xBFFE and 0xBFFF
128  if ((address | 0x0001) == 0xBFFF) {
129  setModeRegister(value);
130  return;
131  }
132 
133  // Write to RAM
134  int regio = (address >> 13) - 2;
135  if (isRamSegment[regio]) {
136  // According to Sean Young
137  // when the regio's are in RAM mode you can read from
138  // the SCC(+) but not write to them
139  // => we assume a write to the memory but maybe
140  // they are just discarded
141  // TODO check this out => ask Sean...
142  if (isMapped[regio]) {
143  internalMemoryBank[regio][address & 0x1FFF] = value;
144  }
145  return;
146  }
147 
148  /* Write to bankswitching registers
149  * The address to change banks:
150  * bank 1: 0x5000 - 0x57FF (0x5000 used)
151  * bank 2: 0x7000 - 0x77FF (0x7000 used)
152  * bank 3: 0x9000 - 0x97FF (0x9000 used)
153  * bank 4: 0xB000 - 0xB7FF (0xB000 used)
154  */
155  if ((address & 0x1800) == 0x1000) {
156  setMapper(regio, value);
157  return;
158  }
159 
160  // call writeMemInterface of SCC if needed
161  switch (enable) {
162  case EN_NONE:
163  // do nothing
164  break;
165  case EN_SCC:
166  if ((0x9800 <= address) && (address < 0xA000)) {
167  scc.writeMem(address & 0xFF, value, time);
168  }
169  break;
170  case EN_SCCPLUS:
171  if ((0xB800 <= address) && (address < 0xC000)) {
172  scc.writeMem(address & 0xFF, value, time);
173  }
174  break;
175  }
176 }
177 
179 {
180  if ((0x4000 <= start) && (start < 0xC000)) {
181  if (start == (0xBFFF & CacheLine::HIGH)) {
182  return nullptr;
183  }
184  int regio = (start >> 13) - 2;
185  if (isRamSegment[regio] && isMapped[regio]) {
186  return &internalMemoryBank[regio][start & 0x1FFF];
187  }
188  return nullptr;
189  }
190  return unmappedWrite;
191 }
192 
193 
194 void MSXSCCPlusCart::setMapper(int regio, byte value)
195 {
196  mapper[regio] = value;
197  value &= mapperMask;
198 
199  byte* block = [&] {
200  if ((!lowRAM && (value < 8)) ||
201  (!highRAM && (value >= 8))) {
202  isMapped[regio] = false;
203  return unmappedRead;
204  } else {
205  isMapped[regio] = true;
206  return &ram[0x2000 * value];
207  }
208  }();
209 
210  checkEnable(); // invalidateDeviceRWCache() done below
211  internalMemoryBank[regio] = block;
212  invalidateDeviceRWCache(0x4000 + regio * 0x2000, 0x2000);
213 }
214 
215 void MSXSCCPlusCart::setModeRegister(byte value)
216 {
217  modeRegister = value;
218  checkEnable(); // invalidateDeviceRWCache() done below
219 
220  if (modeRegister & 0x20) {
222  } else {
224  }
225 
226  if (modeRegister & 0x10) {
227  isRamSegment[0] = true;
228  isRamSegment[1] = true;
229  isRamSegment[2] = true;
230  isRamSegment[3] = true;
231  } else {
232  isRamSegment[0] = (modeRegister & 0x01) == 0x01;
233  isRamSegment[1] = (modeRegister & 0x02) == 0x02;
234  isRamSegment[2] = (modeRegister & 0x24) == 0x24; // extra requirement: SCC+ mode
235  isRamSegment[3] = false;
236  }
237  invalidateDeviceRWCache(0x4000, 0x8000);
238 }
239 
240 void MSXSCCPlusCart::checkEnable()
241 {
242  if ((modeRegister & 0x20) && (mapper[3] & 0x80)) {
243  enable = EN_SCCPLUS;
244  } else if ((!(modeRegister & 0x20)) && ((mapper[2] & 0x3F) == 0x3F)) {
245  enable = EN_SCC;
246  } else {
247  enable = EN_NONE;
248  }
249 }
250 
251 
252 template<typename Archive>
253 void MSXSCCPlusCart::serialize(Archive& ar, unsigned /*version*/)
254 {
255  // These are constants:
256  // mapperMask, lowRAM, highRAM
257 
258  // only serialize that part of the Ram object that's actually
259  // present in the cartridge
260  unsigned ramSize = (lowRAM && highRAM && (mapperMask == 0xF))
261  ? 0x20000 : 0x10000;
262  unsigned ramBase = lowRAM ? 0x00000 : 0x10000;
263  ar.serialize_blob("ram", &ram[ramBase], ramSize);
264 
265  ar.serialize("scc", scc,
266  "mapper", mapper,
267  "mode", modeRegister);
268 
269  if (ar.isLoader()) {
270  // recalculate: isMapped[4], internalMemoryBank[4]
271  for (int i = 0; i < 4; ++i) {
272  setMapper(i, mapper[i]);
273  }
274  // recalculate: enable, isRamSegment[4]
275  setModeRegister(modeRegister);
276  }
277 }
280 
281 } // namespace openmsx
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:32
FileException.hh
serialize.hh
openmsx::File::getSize
size_t getSize()
Returns the size of this file.
Definition: File.cc:103
openmsx::FileContext::resolve
std::string resolve(std::string_view filename) const
Definition: FileContext.cc:80
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
openmsx::MSXSCCPlusCart::getReadCacheLine
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: MSXSCCPlusCart.cc:103
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
openmsx::MSXSCCPlusCart::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: MSXSCCPlusCart.cc:120
openmsx::DeviceConfig::findChild
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:61
ranges.hh
openmsx::MSXSCCPlusCart::serialize
void serialize(Archive &ar, unsigned version)
Definition: MSXSCCPlusCart.cc:253
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::SCC::reset
void reset(EmuTime::param time)
Definition: SCC.cc:172
XMLElement.hh
openmsx::CacheLine::HIGH
constexpr unsigned HIGH
Definition: CacheLine.hh:10
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::SCC::readMem
byte readMem(byte address, EmuTime::param time)
Definition: SCC.cc:192
openmsx::MSXSCCPlusCart::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: MSXSCCPlusCart.cc:65
openmsx::MSXSCCPlusCart
Definition: MSXSCCPlusCart.hh:15
openmsx::XMLElement
Definition: XMLElement.hh:16
openmsx::SCC
Definition: SCC.hh:12
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:742
openmsx::MSXSCCPlusCart::powerUp
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: MSXSCCPlusCart.cc:59
File.hh
openmsx::MSXSCCPlusCart::MSXSCCPlusCart
MSXSCCPlusCart(const DeviceConfig &config)
Definition: MSXSCCPlusCart.cc:15
openmsx::MSXDevice::getCurrentTime
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
openmsx::DeviceConfig::getChildData
const std::string & getChildData(std::string_view name) const
Definition: DeviceConfig.cc:43
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
openmsx::SCC::powerUp
void powerUp(EmuTime::param time)
Definition: SCC.cc:140
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::MSXSCCPlusCart::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: MSXSCCPlusCart.cc:76
openmsx::FileException
Definition: FileException.hh:9
CacheLine.hh
openmsx::MSXDevice::invalidateDeviceRWCache
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:208
FileContext.hh
openmsx::SCC::peekMem
byte peekMem(byte address, EmuTime::param time) const
Definition: SCC.cc:205
openmsx::File
Definition: File.hh:16
openmsx::MSXDevice::unmappedRead
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:300
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::SCC::SCC_Compatible
@ SCC_Compatible
Definition: SCC.hh:14
openmsx::File::read
void read(void *buffer, size_t num)
Read from file.
Definition: File.cc:83
MSXSCCPlusCart.hh
openmsx::SCC::setChipMode
void setChipMode(ChipMode newMode)
Definition: SCC.cc:182
openmsx::DeviceConfig::getFileContext
const FileContext & getFileContext() const
Definition: DeviceConfig.cc:9
ranges::fill
void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:191
openmsx::SCC::writeMem
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:284
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::MSXSCCPlusCart::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: MSXSCCPlusCart.cc:86
openmsx::Ram::getSize
unsigned getSize() const
Definition: Ram.hh:33
openmsx::SCC::SCC_plusmode
@ SCC_plusmode
Definition: SCC.hh:14
openmsx::MSXSCCPlusCart::getWriteCacheLine
byte * getWriteCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: MSXSCCPlusCart.cc:178