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