openMSX
MegaFlashRomSCCPlusSD.cc
Go to the documentation of this file.
3 #include "MSXCPUInterface.hh"
4 #include "CacheLine.hh"
5 #include "CheckedRam.hh"
6 #include "SdCard.hh"
7 #include "enumerate.hh"
8 #include "ranges.hh"
9 #include "serialize.hh"
10 #include "xrange.hh"
11 #include <array>
12 #include <memory>
13 
14 /******************************************************************************
15  * DOCUMENTATION AS PROVIDED BY MANUEL PAZOS, WHO DEVELOPED THE CARTRIDGE *
16  ******************************************************************************
17 
18 --------------------------------------------------------------------------------
19 MegaFlashROM SCC+ SD Technical Details
20 (c) Manuel Pazos 24-02-2014
21 --------------------------------------------------------------------------------
22 
23 [Main features]
24 
25  - 8192 KB flashROM memory
26  - SD interface (MegaSD)
27  - SCC-I (2312P001)
28  - PSG (AY-3-8910/YM2149)
29  - Mappers: ASCII8, ASCII16, Konami, Konami SCC, linear 64K
30  - Slot expander
31 
32 
33 --------------------------------------------------------------------------------
34 [Memory]
35 
36  - Model Numonix/Micron M29W640FB/M29W640GB TSOP48
37  - Datasheet: http://www.micron.com/~/media/Documents/Products/Data%20Sheet/NOR%20Flash/Parallel/M29W/M29W640F.pdf
38  - Block layout:
39  #00000 8K x 8
40  #10000 64K x 127
41  - Command addresses:
42  #4555 and #4AAA
43  - FlashROM ID:
44  ID_M29W640FB #FD
45  ID_M29W640GB #7E
46 
47 
48 --------------------------------------------------------------------------------
49 [PSG]
50 
51  The PSG included in the cartridge is mapped to ports #10-#12
52 
53  Port #A0 -> #10
54  Port #A1 -> #11
55  Port #A2 -> #12
56 
57  The PSG is read only.
58 
59 --------------------------------------------------------------------------------
60 [Cartridge layout]
61 
62  - Subslot 0: Recovery - 16K linear (Visible on page 1 and 2)
63  - Subslot 1: MegaFlashROM SCC+ - 7104K (multiple mapper support)
64  - Subslot 2: RAM (when available)
65  - Subslot 3: MegaSD - 1024K (ASC8 mapper)
66 
67 
68 --------------------------------------------------------------------------------
69 [FlashROM layout]
70 
71 #000000+----------------+
72  | Recovery | 16K - Subslot 0 (Note: Blocks are write protected
73 by VPP/WD pin)
74  +----------------+
75  | DSK Kernel | 16K
76  +----------------+
77  | Not used | 32K
78 #010000+----------------+
79  | |
80  | |
81  | MegaFlashROM | 7104K - Subslot 1
82  | |
83  | |
84 #700000+----------------+
85  | |
86  | MegaSD | 1024K - Subslot 3
87  | |
88  +----------------+
89 
90 
91 --------------------------------------------------------------------------------
92 [Subslot register (#FFFF)]
93 
94  Available when writing at #FFFF in the cartridge slot.
95  Reading that address will return all the bits inverted.
96  Default value = 0
97 
98 
99 --------------------------------------------------------------------------------
100 [Subslot 0: RECOVERY]
101 
102  Size 16K
103  Common ROM (Without mapper).
104  Visible on pages 1 and 2 (mirrored all over the slot)
105 
106 
107 --------------------------------------------------------------------------------
108 [Subslot 1: MegaFlashROM SCC+ SD]
109 
110  [REGISTERS]
111 
112  [MAPPER REGISTER (#7FFF)]
113  7 mapper mode 1: \ #00 = SCC, #40 = 64K
114  6 mapper mode 0: / #80 = ASC8, #C0 = ASC16
115  5 mapper mode : Select Konami mapper (0=SCC or 1=normal)
116  4
117  3 Disable #4000-#5FFF mapper in Konami mode
118  2 Disable this mapper register #7FFF
119  1 Disable mapper and offset registers
120  0 Enable 512K mapper limit in SCC mapper or 256K limit in Konami mapper
121 
122 
123  [OFFSET REGISTER (#7FFD)]
124  7-0 Offset value bits 7-0
125 
126 
127  [OFFSET REGISTER (#7FFE)]
128  1 Offset bit 9
129  0 Offset bit 8
130 
131 
132  [CONFIG REGISTER (#7FFC)]
133  7 Disable config register (1 = Disabled)
134  6
135  5 Disable SRAM (i.e. the RAM in subslot 2)
136  4 DSK mode (1 = On): Bank 0 and 1 are remaped to DSK kernel (config banks 2-3)
137  3 Cartridge PSG also mapped to ports #A0-#A3
138  2 Subslots disabled (1 = Disabled) Only MegaflashROM SCC+ is available.
139  1 FlashROM Block protect (1 = Protect) VPP_WD pin
140  0 FlashROM write enable (1 = Enabled)
141 
142 
143 
144  [MAPPERS]
145 
146  - ASCII 8: Common ASC8 mapper
147 
148  - ASCII 16: Common ASC16 mapper
149 
150  - Konami: Common Konami mapper.
151  Bank0 (#4000-#5FFF) can be also changed unless [MAPPER REGISTER] bit 3 is 1
152 
153  - Konami SCC: Common Konami SCC mapper
154 
155  - Linear 64: #0000-#3FFF bank0
156  #4000-#7FFF bank1
157  #8000-#BFFF bank2
158  #C000-#FFFF bank3
159  Banks mapper registers addresses = Konami
160 
161 
162  [DEFAULT VALUES]
163 
164  - MAPPER REGISTER = 0
165  - CONFIG REGISTER = %00000011
166  - MapperBank0 = 0
167  - MapperBank1 = 1
168  - MapperBank2 = 2
169  - MapperBank3 = 3
170  - BankOffset = 0
171  - Subslot register = 0
172 
173 
174  [LOGIC]
175 
176  Bank0 <= "1111111010" when CONFIG REGISTER(4) = '1' and MapperBank0 = "0000000000" else ; DSK mode
177  MapperBank0 + bankOffset;
178 
179  Bank1 <= "1111111011" when CONFIG REGISTER(4) = '1' and MapperBank1 = "0000000001" else ; DSK mode
180  MapperBank1 + bankOffset;
181 
182  Bank2 <= MapperBank2 + bankOffset;
183 
184  Bank3 <= MapperBank3 + bankOffset;
185 
186 
187  RamAdr <=
188  -- Mapper in 64K mode
189  Bank0(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "00" else --#0000-#3FFF
190  Bank1(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "01" else --#4000-#7FFF
191  Bank2(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "10" else --#8000-#BFFF
192  Bank3(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "11" else --#C000-#FFFF
193 
194  -- Mapper in SCC, ASC8 or ASC16 modes
195  Bank0(9 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "10" else --#4000-#5FFF
196  Bank1(9 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "11" else --#6000-#7FFF
197  Bank2(9 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "00" else --#8000-#9FFF
198  Bank3(9 downto 0) & adr(12 downto 0); --#A000-#BFFF
199 
200 
201  Note: It is possible to access the whole flashROM from the MegaFlashROM SCC+
202  SD using the offsets register!
203 
204 --------------------------------------------------------------------------------
205 [Subslot 2: 512K RAM expansion]
206 
207  Mapper ports:
208  Page 0 = #FC
209  Page 1 = #FD
210  Page 2 = #FE
211  Page 3 = #FF
212 
213  Default bank values:
214  Page 0 = 3
215  Page 1 = 2
216  Page 2 = 1
217  Page 3 = 0
218 
219  Disabled when [CONFIG REGISTER] bit 5 = 1
220 
221  Since mapper ports must not be read, as stated on MSX Technical Handbook, and
222  mapper ports as read only, as stated on MSX Datapack, all read operations on
223  these ports will not return any value.
224 
225 UPDATE:
226  Initial version indeed did not support reading the memory mapper ports. But
227  upon user request this feature was added later.
228 
229 --------------------------------------------------------------------------------
230 [Subslot 3: MegaSD]
231 
232  Mapper type: ASCII8
233 
234  Default mapper values:
235  Bank0 = 0
236  Bank1 = 1
237  Bank2 = 0
238  Bank3 = 0
239 
240  Memory range 1024K: Banks #00-#7F are mirrored in #80-#FF (except registers
241  bank #40)
242 
243  Memory registers area (Bank #40):
244  #4000-#57FF: SD card access (R/W)
245  #4000-#4FFF: /CS signal = 0 - SD enabled
246  #5000-#5FFF: /CS signal = 1 - SD disabled
247 
248  #5800-#5FFF: SD slot select (bit 0: 0 = SD slot 1, 1 = SD slot 2)
249 
250  Cards work in SPI mode.
251  Signals used: CS, DI, DO, SCLK
252  When reading, 8 bits are read from DO
253  When writing, 8 bits are written to DI
254 
255  SD specifications: https://www.sdcard.org/downloads/pls/simplified_specs/part1_410.pdf
256 
257 ******************************************************************************/
258 
259 constexpr unsigned MEMORY_MAPPER_SIZE = 512;
260 constexpr unsigned MEMORY_MAPPER_MASK = (MEMORY_MAPPER_SIZE / 16) - 1;
261 
262 namespace openmsx {
263 
264 static constexpr auto sectorInfo = [] {
265  // 8 * 8kB, followed by 127 * 64kB
266  using Info = AmdFlash::SectorInfo;
267  std::array<Info, 8 + 127> result = {};
268  std::fill(result.begin(), result.begin() + 8, Info{ 8 * 1024, false});
269  std::fill(result.begin() + 8, result.end(), Info{64 * 1024, false});
270  return result;
271 }();
272 
273 
275  : MSXDevice(config)
276  , flash("MFR SCC+ SD flash", sectorInfo, 0x207E,
277  AmdFlash::Addressing::BITS_12, config)
278  , scc("MFR SCC+ SD SCC-I", config, getCurrentTime(), SCC::SCC_Compatible)
279  , psg("MFR SCC+ SD PSG", DummyAY8910Periphery::instance(), config,
280  getCurrentTime())
281  , configReg(3) // avoid UMR
282  , checkedRam(config.getChildDataAsBool("hasmemorymapper", true) ?
283  std::make_unique<CheckedRam>(config, getName() + " memory mapper", "memory mapper", MEMORY_MAPPER_SIZE * 1024)
284  : nullptr)
285  , mapperIO(checkedRam ? std::make_unique<MapperIO>(*this) : nullptr) // handles ports 0xfc-0xff
286 {
288 
289  getCPUInterface().register_IO_Out(0x10, this);
290  getCPUInterface().register_IO_Out(0x11, this);
291 
292  sdCard[0] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild("sdcard1")));
293  sdCard[1] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild("sdcard2")));
294 }
295 
297 {
298  // unregister extra PSG I/O ports
299  updateConfigReg(3);
300 
301  getCPUInterface().unregister_IO_Out(0x10, this);
302  getCPUInterface().unregister_IO_Out(0x11, this);
303 }
304 
305 void MegaFlashRomSCCPlusSD::powerUp(EmuTime::param time)
306 {
307  scc.powerUp(time);
308  reset(time);
309 }
310 
311 void MegaFlashRomSCCPlusSD::reset(EmuTime::param time)
312 {
313  mapperReg = 0;
314  offsetReg = 0;
315  updateConfigReg(3);
316  subslotReg = 0;
317  ranges::iota(bankRegsSubSlot1, 0);
318 
319  sccMode = 0;
320  ranges::iota(sccBanks, 0);
321  scc.reset(time);
322 
323  psgLatch = 0;
324  psg.reset(time);
325 
326  flash.reset();
327 
328  // memory mapper
329  for (auto [i, mr] : enumerate(memMapperRegs)) {
330  mr = byte(3 - i);
331  }
332 
333  for (auto [bank, reg] : enumerate(bankRegsSubSlot3)) {
334  reg = (bank == 1) ? 1 : 0;
335  }
336 
337  selectedCard = 0;
338 
339  invalidateDeviceRWCache(); // flush all to be sure
340 }
341 
342 byte MegaFlashRomSCCPlusSD::getSubSlot(unsigned addr) const
343 {
344  return isSlotExpanderEnabled() ?
345  (subslotReg >> (2 * (addr >> 14))) & 3 : 1;
346 }
347 
348 void MegaFlashRomSCCPlusSD::writeToFlash(unsigned addr, byte value)
349 {
350  if (isFlashRomWriteEnabled()) {
351  flash.write(addr, value);
352  } else {
353  // flash is write protected, this is implemented by not passing
354  // writes to flash at all.
355  }
356 }
357 
358 byte MegaFlashRomSCCPlusSD::peekMem(word addr, EmuTime::param time) const
359 {
360  if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
361  // read subslot register
362  return subslotReg ^ 0xFF;
363  }
364 
365  switch (getSubSlot(addr)) {
366  case 0: return peekMemSubSlot0(addr);
367  case 1: return peekMemSubSlot1(addr, time);
368  case 2: return isMemoryMapperEnabled() ?
369  peekMemSubSlot2(addr) : 0xFF;
370  case 3: return peekMemSubSlot3(addr, time);
371  default: UNREACHABLE; return 0;
372  }
373 }
374 
375 byte MegaFlashRomSCCPlusSD::readMem(word addr, EmuTime::param time)
376 {
377  if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
378  // read subslot register
379  return subslotReg ^ 0xFF;
380  }
381 
382  switch (getSubSlot(addr)) {
383  case 0: return readMemSubSlot0(addr);
384  case 1: return readMemSubSlot1(addr, time);
385  case 2: return isMemoryMapperEnabled() ?
386  readMemSubSlot2(addr) : 0xFF;
387  case 3: return readMemSubSlot3(addr, time);
388  default: UNREACHABLE; return 0;
389  }
390 }
391 
393 {
394  if (isSlotExpanderEnabled() &&
395  ((addr & CacheLine::HIGH) == (0xFFFF & CacheLine::HIGH))) {
396  // read subslot register
397  return nullptr;
398  }
399 
400  switch (getSubSlot(addr)) {
401  case 0: return getReadCacheLineSubSlot0(addr);
402  case 1: return getReadCacheLineSubSlot1(addr);
403  case 2: return isMemoryMapperEnabled() ?
404  getReadCacheLineSubSlot2(addr) : unmappedRead;
405  case 3: return getReadCacheLineSubSlot3(addr);
406  default: UNREACHABLE; return nullptr;
407  }
408 }
409 
410 void MegaFlashRomSCCPlusSD::writeMem(word addr, byte value, EmuTime::param time)
411 {
412  if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
413  // write subslot register
414  byte diff = value ^ subslotReg;
415  subslotReg = value;
416  for (auto i : xrange(4)) {
417  if (diff & (3 << (2 * i))) {
418  invalidateDeviceRWCache(0x4000 * i, 0x4000);
419  }
420  }
421  }
422 
423  switch (getSubSlot(addr)) {
424  case 0: writeMemSubSlot0(addr, value); break;
425  case 1: writeMemSubSlot1(addr, value, time); break;
426  case 2: if (isMemoryMapperEnabled()) {
427  writeMemSubSlot2(addr, value);
428  }
429  break;
430  case 3: writeMemSubSlot3(addr, value, time); break;
431  default: UNREACHABLE;
432  }
433 }
434 
436 {
437  if (isSlotExpanderEnabled() &&
438  ((addr & CacheLine::HIGH) == (0xFFFF & CacheLine::HIGH))) {
439  // read subslot register
440  return nullptr;
441  }
442 
443  switch (getSubSlot(addr)) {
444  case 0: return getWriteCacheLineSubSlot0(addr);
445  case 1: return getWriteCacheLineSubSlot1(addr);
446  case 2: return isMemoryMapperEnabled() ?
447  getWriteCacheLineSubSlot2(addr) : unmappedWrite;
448  case 3: return getWriteCacheLineSubSlot3(addr);
449  default: UNREACHABLE; return nullptr;
450  }
451 }
452 
454 
455 byte MegaFlashRomSCCPlusSD::readMemSubSlot0(word addr)
456 {
457  // read from the first 16kB of flash
458  // Pazos: ROM and flash can be accessed in all pages (0,1,2,3) (#0000-#FFFF)
459  return flash.read(addr & 0x3FFF);
460 }
461 
462 byte MegaFlashRomSCCPlusSD::peekMemSubSlot0(word addr) const
463 {
464  // read from the first 16kB of flash
465  // Pazos: ROM and flash can be accessed in all pages (0,1,2,3) (#0000-#FFFF)
466  return flash.peek(addr & 0x3FFF);
467 }
468 
469 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot0(word addr) const
470 {
471  return flash.getReadCacheLine(addr & 0x3FFF);
472 }
473 
474 void MegaFlashRomSCCPlusSD::writeMemSubSlot0(word addr, byte value)
475 {
476  // Pazos: ROM and flash can be accessed in all pages (0,1,2,3) (#0000-#FFFF)
477  writeToFlash(addr & 0x3FFF, value);
478 }
479 
480 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot0(word /*addr*/) const
481 {
482  return nullptr; // flash isn't cacheable
483 }
484 
486 
487 void MegaFlashRomSCCPlusSD::updateConfigReg(byte value)
488 {
489  if ((value ^ configReg) & 0x08) {
490  if (value & 0x08) {
491  getCPUInterface().register_IO_Out(0xA0, this);
492  getCPUInterface().register_IO_Out(0xA1, this);
493  } else {
494  getCPUInterface().unregister_IO_Out(0xA0, this);
495  getCPUInterface().unregister_IO_Out(0xA1, this);
496  }
497  }
498  configReg = value;
499  flash.setVppWpPinLow(isFlashRomBlockProtectEnabled());
500  invalidateDeviceRWCache(); // flush all to be sure
501 }
502 
503 MegaFlashRomSCCPlusSD::SCCEnable MegaFlashRomSCCPlusSD::getSCCEnable() const
504 {
505  if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
506  return EN_SCCPLUS;
507  } else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
508  return EN_SCC;
509  } else {
510  return EN_NONE;
511  }
512 }
513 
514 unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot1(unsigned addr) const
515 {
516  unsigned page = is64KmapperConfigured() ? (addr >> 14) : ((addr >> 13) - 2);
517  unsigned size = is64KmapperConfigured() ? 0x4000 : 0x2000;
518 
519  if (page >= 4) return unsigned(-1); // outside [0x4000, 0xBFFF] for non-64K mapper
520 
521  unsigned bank = bankRegsSubSlot1[page];
522  if (isDSKmodeEnabled() && (page == 0) && (bank == 0)) {
523  bank = 0x3FA;
524  } else if (isDSKmodeEnabled() && (page == 1) && (bank == 1)) {
525  bank = 0x3FB;
526  } else { // not DSK mode
527  bank += offsetReg;
528  }
529 
530  unsigned tmp = (bank * size) + (addr & (size - 1));
531  return (tmp + 0x010000) & 0x7FFFFF; // wrap at 8MB
532 }
533 
534 byte MegaFlashRomSCCPlusSD::readMemSubSlot1(word addr, EmuTime::param time)
535 {
536  if (isKonamiSCCmapperConfigured()) { // Konami SCC
537  SCCEnable enable = getSCCEnable();
538  if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
539  ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
540  byte val = scc.readMem(addr & 0xFF, time);
541  return val;
542  }
543  }
544 
545  unsigned flashAddr = getFlashAddrSubSlot1(addr);
546  return (flashAddr != unsigned(-1))
547  ? flash.read(flashAddr)
548  : 0xFF; // unmapped read
549 }
550 
551 byte MegaFlashRomSCCPlusSD::peekMemSubSlot1(word addr, EmuTime::param time) const
552 {
553  if (isKonamiSCCmapperConfigured()) { // Konami SCC
554  SCCEnable enable = getSCCEnable();
555  if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
556  ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
557  byte val = scc.peekMem(addr & 0xFF, time);
558  return val;
559  }
560  }
561 
562  unsigned flashAddr = getFlashAddrSubSlot1(addr);
563  return (flashAddr != unsigned(-1))
564  ? flash.peek(flashAddr)
565  : 0xFF; // unmapped read
566 }
567 
568 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot1(word addr) const
569 {
570  if (isKonamiSCCmapperConfigured()) {
571  SCCEnable enable = getSCCEnable();
572  if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
573  ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
574  return nullptr;
575  }
576  }
577 
578  unsigned flashAddr = getFlashAddrSubSlot1(addr);
579  return (flashAddr != unsigned(-1))
580  ? flash.getReadCacheLine(flashAddr)
581  : unmappedRead;
582 }
583 
584 void MegaFlashRomSCCPlusSD::writeMemSubSlot1(word addr, byte value, EmuTime::param time)
585 {
586  // address is calculated before writes to other regions take effect
587  unsigned flashAddr = getFlashAddrSubSlot1(addr);
588 
589  // There are several overlapping functional regions in the address
590  // space. A single write can trigger behaviour in multiple regions. In
591  // other words there's no priority amongst the regions where a higher
592  // priority region blocks the write from the lower priority regions.
593  // This only goes for places where the flash is 'seen', so not for the
594  // SCC registers and the SSR
595 
596  if (!isConfigRegDisabled() && (addr == 0x7FFC)) {
597  // write config register
598  updateConfigReg(value);
599  }
600 
601  if (!isMapperRegisterDisabled() && (addr == 0x7FFF)) {
602  // write mapper register
603  mapperReg = value;
604  invalidateDeviceRWCache(); // flush all to be sure
605  }
606 
607  if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
608  // write offset register low part
609  offsetReg = (offsetReg & 0x300) | value;
611  }
612 
613  if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
614  // write offset register high part (bit 8 and 9)
615  offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
617  }
618 
619  if (isKonamiSCCmapperConfigured()) {
620  // Konami-SCC
621  if ((addr & 0xFFFE) == 0xBFFE) {
622  sccMode = value;
623  scc.setChipMode((value & 0x20) ? SCC::SCC_plusmode
625  invalidateDeviceRWCache(0x9800, 0x800);
626  invalidateDeviceRWCache(0xB800, 0x800);
627  }
628  SCCEnable enable = getSCCEnable();
629  bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
630  ((sccMode & 0x10) == 0x10);
631  bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
632  if (((enable == EN_SCC) && !isRamSegment2 &&
633  (0x9800 <= addr) && (addr < 0xA000)) ||
634  ((enable == EN_SCCPLUS) && !isRamSegment3 &&
635  (0xB800 <= addr) && (addr < 0xC000))) {
636  scc.writeMem(addr & 0xFF, value, time);
637  return; // Pazos: when SCC registers are selected flashROM is not seen, so it does not accept commands.
638  }
639  }
640 
641  unsigned page8kB = (addr >> 13) - 2;
642  if (!areBankRegsAndOffsetRegsDisabled() && (page8kB < 4)) {
643  // (possibly) write to bank registers
644  switch (mapperReg & 0xE0) {
645  case 0x00:
646  // Konami-SCC
647  if ((addr & 0x1800) == 0x1000) {
648  // Storing 'sccBanks' may seem redundant at
649  // first, but it's required to calculate
650  // whether the SCC is enabled or not.
651  sccBanks[page8kB] = value;
652  // Masking of the mapper bits is done on
653  // write (and only in Konami(-scc) mode)
654  byte mask = areKonamiMapperLimitsEnabled() ? 0x3F : 0xFF;
655  bankRegsSubSlot1[page8kB] = value & mask;
656  invalidateDeviceRWCache(0x4000 + 0x2000 * page8kB, 0x2000);
657  }
658  break;
659  case 0x20: {
660  // Konami
661  if (isWritingKonamiBankRegisterDisabled() && (addr < 0x6000)) {
662  // Switching 0x4000-0x5FFF disabled.
663  // This bit blocks writing to the bank register
664  // (an alternative was forcing a 0 on read).
665  // It only has effect in Konami mode.
666  break;
667  }
668  // Making of the mapper bits is done on
669  // write (and only in Konami(-scc) mode)
670  if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000))) break; // only SCC range works
671  byte mask = areKonamiMapperLimitsEnabled() ? 0x1F : 0xFF;
672  bankRegsSubSlot1[page8kB] = value & mask;
673  invalidateDeviceRWCache(0x4000 + 0x2000 * page8kB, 0x2000);
674  break;
675  }
676  case 0x40:
677  case 0x60:
678  // 64kB
679  bankRegsSubSlot1[page8kB] = value;
680  invalidateDeviceRWCache(0x0000 + 0x4000 * page8kB, 0x4000);
681  break;
682  case 0x80:
683  case 0xA0:
684  // ASCII-8
685  if ((0x6000 <= addr) && (addr < 0x8000)) {
686  byte bank = (addr >> 11) & 0x03;
687  bankRegsSubSlot1[bank] = value;
688  invalidateDeviceRWCache(0x4000 + 0x2000 * bank, 0x2000);
689  }
690  break;
691  case 0xC0:
692  case 0xE0:
693  // ASCII-16
694  // This behaviour is confirmed by Manuel Pazos (creator
695  // of the cartridge): ASCII-16 uses all 4 bank registers
696  // and one bank switch changes 2 registers at once.
697  // This matters when switching mapper mode, because
698  // the content of the bank registers is unchanged after
699  // a switch.
700  if ((0x6000 <= addr) && (addr < 0x6800)) {
701  bankRegsSubSlot1[0] = 2 * value + 0;
702  bankRegsSubSlot1[1] = 2 * value + 1;
703  invalidateDeviceRWCache(0x4000, 0x4000);
704  }
705  if ((0x7000 <= addr) && (addr < 0x7800)) {
706  bankRegsSubSlot1[2] = 2 * value + 0;
707  bankRegsSubSlot1[3] = 2 * value + 1;
708  invalidateDeviceRWCache(0x8000, 0x4000);
709  }
710  break;
711  }
712  }
713 
714  if (flashAddr != unsigned(-1)) {
715  writeToFlash(flashAddr, value);
716  }
717 }
718 
719 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(word /*addr*/) const
720 {
721  return nullptr; // flash isn't cacheable
722 }
723 
725 
726 unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(word address) const
727 {
728  unsigned bank = memMapperRegs[address >> 14];
729  return ((bank & MEMORY_MAPPER_MASK) << 14) | (address & 0x3FFF);
730 }
731 
732 byte MegaFlashRomSCCPlusSD::readMemSubSlot2(word addr)
733 {
734  // read from the memory mapper
735  return checkedRam->read(calcMemMapperAddress(addr));
736 }
737 
738 byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(word addr) const
739 {
740  return checkedRam->peek(calcMemMapperAddress(addr));
741 }
742 
743 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(word addr) const
744 {
745  return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
746 }
747 
748 void MegaFlashRomSCCPlusSD::writeMemSubSlot2(word addr, byte value)
749 {
750  // write to the memory mapper
751  checkedRam->write(calcMemMapperAddress(addr), value);
752 }
753 
754 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(word addr) const
755 {
756  return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
757 }
758 
759 byte MegaFlashRomSCCPlusSD::MapperIO::readIO(word port, EmuTime::param time)
760 {
761  return peekIO(port, time);
762 }
763 
764 byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(word port, EmuTime::param /*time*/) const
765 {
766  return getSelectedSegment(port & 3) | ~MEMORY_MAPPER_MASK;
767 }
768 
769 void MegaFlashRomSCCPlusSD::MapperIO::writeIO(word port, byte value, EmuTime::param /*time*/)
770 {
771  mega.memMapperRegs[port & 3] = value & MEMORY_MAPPER_MASK;
772  mega.invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
773 }
774 
775 byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(byte page) const
776 {
777  return mega.memMapperRegs[page];
778 }
779 
781 
782 unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(unsigned addr) const
783 {
784  unsigned page8kB = (addr >> 13) - 2;
785  return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
786 }
787 
788 byte MegaFlashRomSCCPlusSD::readMemSubSlot3(word addr, EmuTime::param /*time*/)
789 {
790  if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
791  // transfer from SD card
792  return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
793  }
794 
795  if ((0x4000 <= addr) && (addr < 0xC000)) {
796  // read (flash)rom content
797  unsigned flashAddr = getFlashAddrSubSlot3(addr);
798  return flash.read(flashAddr);
799  } else {
800  // unmapped read
801  return 0xFF;
802  }
803 }
804 
805 byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(word addr, EmuTime::param /*time*/) const
806 {
807  if ((0x4000 <= addr) && (addr < 0xC000)) {
808  // read (flash)rom content
809  unsigned flashAddr = getFlashAddrSubSlot3(addr);
810  return flash.peek(flashAddr);
811  } else {
812  // unmapped read
813  return 0xFF;
814  }
815 }
816 
817 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(word addr) const
818 {
819  if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
820  return nullptr;
821  }
822 
823  if ((0x4000 <= addr) && (addr < 0xC000)) {
824  // (flash)rom content
825  unsigned flashAddr = getFlashAddrSubSlot3(addr);
826  return flash.getReadCacheLine(flashAddr);
827  } else {
828  return unmappedRead;
829  }
830 }
831 
832 void MegaFlashRomSCCPlusSD::writeMemSubSlot3(word addr, byte value, EmuTime::param /*time*/)
833 {
834 
835  if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
836  if (addr >= 0x5800) {
837  selectedCard = value & 1;
838  } else {
839  // transfer to SD card
840  sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0); // ignore return value
841  }
842  }
843 
844  // write to flash (first, before modifying bank regs)
845  if ((0x4000 <= addr) && (addr < 0xC000)) {
846  unsigned flashAddr = getFlashAddrSubSlot3(addr);
847  writeToFlash(flashAddr, value);
848  }
849 
850  // ASCII-8 mapper
851  if ((0x6000 <= addr) && (addr < 0x8000)) {
852  byte page8kB = (addr >> 11) & 0x03;
853  bankRegsSubSlot3[page8kB] = value;
854  invalidateDeviceRWCache(0x4000 + 0x2000 * page8kB, 0x2000);
855  }
856 }
857 
858 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(word /*addr*/) const
859 {
860  return nullptr; // flash isn't cacheable
861 }
862 
864 
865 void MegaFlashRomSCCPlusSD::writeIO(word port, byte value, EmuTime::param time)
866 {
867  switch (port & 0xFF) {
868  case 0xA0:
869  if (!isPSGalsoMappedToNormalPorts()) return;
870  [[fallthrough]];
871  case 0x10:
872  psgLatch = value & 0x0F;
873  break;
874 
875  case 0xA1:
876  if (!isPSGalsoMappedToNormalPorts()) return;
877  [[fallthrough]];
878  case 0x11:
879  psg.writeRegister(psgLatch, value, time);
880  break;
881 
882  default:
883  UNREACHABLE;
884  }
885 }
886 
887 template<typename Archive>
888 void MegaFlashRomSCCPlusSD::serialize(Archive& ar, unsigned /*version*/)
889 {
890  // skip MSXRom base class
891  ar.template serializeBase<MSXDevice>(*this);
892 
893  // overall
894  ar.serialize("flash", flash,
895  "subslotReg", subslotReg);
896 
897  // subslot 0 stuff
898  // (nothing)
899 
900  // subslot 1 stuff
901  ar.serialize("scc", scc,
902  "sccMode", sccMode,
903  "sccBanks", sccBanks,
904  "psg", psg,
905  "psgLatch", psgLatch,
906  "configReg", configReg,
907  "mapperReg", mapperReg,
908  "offsetReg", offsetReg,
909  "bankRegsSubSlot1", bankRegsSubSlot1);
910  if constexpr (Archive::IS_LOADER) {
911  // Re-register PSG ports (if needed)
912  byte tmp = configReg;
913  configReg = 3; // set to un-registered
914  updateConfigReg(tmp); // restore correct value
915  }
916 
917  // subslot 2 stuff
918  // TODO ar.serialize("checkedRam", checkedRam);
919  if (checkedRam) ar.serialize("ram", checkedRam->getUncheckedRam());
920  ar.serialize("memMapperRegs", memMapperRegs);
921 
922  // subslot 3 stuff
923  ar.serialize("bankRegsSubSlot3", bankRegsSubSlot3,
924  "selectedCard", selectedCard,
925  "sdCard0", *sdCard[0],
926  "sdCard1", *sdCard[1]);
927 }
929 REGISTER_MSXDEVICE(MegaFlashRomSCCPlusSD, "MegaFlashRomSCCPlusSD");
930 
931 } // namespace openmsx
constexpr unsigned MEMORY_MAPPER_MASK
constexpr unsigned MEMORY_MAPPER_SIZE
void reset(EmuTime::param time)
Definition: AY8910.cc:524
void writeRegister(unsigned reg, byte value, EmuTime::param time)
Definition: AY8910.cc:581
void write(unsigned address, byte value)
Definition: AmdFlash.cc:265
byte peek(unsigned address) const
Definition: AmdFlash.cc:212
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
Definition: AmdFlash.hh:63
byte read(unsigned address) const
Definition: AmdFlash.cc:248
const byte * getReadCacheLine(unsigned address) const
Definition: AmdFlash.cc:254
This class keeps track of which bytes in the Ram have been written to.
Definition: CheckedRam.hh:28
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:66
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void unregister_IO_Out(byte port, MSXDevice *device)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:33
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:301
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:209
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:126
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:302
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:134
void serialize(Archive &ar, unsigned version)
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
void reset(EmuTime::param time) override
This method is called on reset.
MegaFlashRomSCCPlusSD(const DeviceConfig &config)
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
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.
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.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:284
void setChipMode(ChipMode newMode)
Definition: SCC.cc:182
void powerUp(EmuTime::param time)
Definition: SCC.cc:140
byte readMem(byte address, EmuTime::param time)
Definition: SCC.cc:192
@ SCC_plusmode
Definition: SCC.hh:14
@ SCC_Compatible
Definition: SCC.hh:14
void reset(EmuTime::param time)
Definition: SCC.cc:172
byte peekMem(byte address, EmuTime::param time) const
Definition: SCC.cc:205
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
constexpr unsigned HIGH
Definition: CacheLine.hh:10
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:727
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
AmdFlash::SectorInfo Info
Definition: RomManbow2.cc:17
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
constexpr nibble mask[4][13]
Definition: RP5C01.cc:34
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:256
constexpr void iota(ForwardIt first, ForwardIt last, T value)
Definition: ranges.hh:263
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1009
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:133