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 "serialize.hh"
8 #include <memory>
9 #include <vector>
10 
11 /******************************************************************************
12  * DOCUMENTATION AS PROVIDED BY MANUEL PAZOS, WHO DEVELOPED THE CARTRIDGE *
13  ******************************************************************************
14 
15 --------------------------------------------------------------------------------
16 MegaFlashROM SCC+ SD Technical Details
17 (c) Manuel Pazos 24-02-2014
18 --------------------------------------------------------------------------------
19 
20 [Main features]
21 
22  - 8192 KB flashROM memory
23  - SD interface (MegaSD)
24  - SCC-I (2312P001)
25  - PSG (AY-3-8910/YM2149)
26  - Mappers: ASCII8, ASCII16, Konami, Konami SCC, linear 64K
27  - Slot expander
28 
29 
30 --------------------------------------------------------------------------------
31 [Memory]
32 
33  - Model Numonix/Micron M29W640FB/M29W640GB TSOP48
34  - Datasheet: http://www.micron.com/~/media/Documents/Products/Data%20Sheet/NOR%20Flash/Parallel/M29W/M29W640F.pdf
35  - Block layout:
36  #00000 8K x 8
37  #10000 64K x 127
38  - Command addresses:
39  #4555 and #4AAA
40  - FlashROM ID:
41  ID_M29W640FB #FD
42  ID_M29W640GB #7E
43 
44 
45 --------------------------------------------------------------------------------
46 [PSG]
47 
48  The PSG included in the cartridge is mapped to ports #10-#12
49 
50  Port #A0 -> #10
51  Port #A1 -> #11
52  Port #A2 -> #12
53 
54  The PSG is read only.
55 
56 --------------------------------------------------------------------------------
57 [Cartridge layout]
58 
59  - Subslot 0: Recovery - 16K linear (Visible on page 1 and 2)
60  - Subslot 1: MegaFlashROM SCC+ - 7104K (multiple mapper support)
61  - Subslot 2: RAM (when available)
62  - Subslot 3: MegaSD - 1024K (ASC8 mapper)
63 
64 
65 --------------------------------------------------------------------------------
66 [FlashROM layout]
67 
68 #000000+----------------+
69  | Recovery | 16K - Subslot 0 (Note: Blocks are write protected
70 by VPP/WD pin)
71  +----------------+
72  | DSK Kernel | 16K
73  +----------------+
74  | Not used | 32K
75 #010000+----------------+
76  | |
77  | |
78  | MegaFlashROM | 7104K - Subslot 1
79  | |
80  | |
81 #700000+----------------+
82  | |
83  | MegaSD | 1024K - Subslot 3
84  | |
85  +----------------+
86 
87 
88 --------------------------------------------------------------------------------
89 [Subslot register (#FFFF)]
90 
91  Available when writing at #FFFF in the cartridge slot.
92  Reading that address will return all the bits inverted.
93  Default value = 0
94 
95 
96 --------------------------------------------------------------------------------
97 [Subslot 0: RECOVERY]
98 
99  Size 16K
100  Common ROM (Without mapper).
101  Visible on pages 1 and 2 (mirrored all over the slot)
102 
103 
104 --------------------------------------------------------------------------------
105 [Subslot 1: MegaFlashROM SCC+ SD]
106 
107  [REGISTERS]
108 
109  [MAPPER REGISTER (#7FFF)]
110  7 mapper mode 1: \ #00 = SCC, #40 = 64K
111  6 mapper mode 0: / #80 = ASC8, #C0 = ASC16
112  5 mapper mode : Select Konami mapper (0=SCC or 1=normal)
113  4
114  3 Disable #4000-#5FFF mapper in Konami mode
115  2 Disable this mapper register #7FFF
116  1 Disable mapper and offset registers
117  0 Enable 512K mapper limit in SCC mapper or 256K limit in Konami mapper
118 
119 
120  [OFFSET REGISTER (#7FFD)]
121  7-0 Offset value bits 7-0
122 
123 
124  [OFFSET REGISTER (#7FFE)]
125  1 Offset bit 9
126  0 Offset bit 8
127 
128 
129  [CONFIG REGISTER (#7FFC)]
130  7 Disable config register (1 = Disabled)
131  6
132  5 Disable SRAM (i.e. the RAM in subslot 2)
133  4 DSK mode (1 = On): Bank 0 and 1 are remaped to DSK kernel (config banks 2-3)
134  3 Cartridge PSG also mapped to ports #A0-#A3
135  2 Subslots disabled (1 = Disabled) Only MegaflashROM SCC+ is available.
136  1 FlashROM Block protect (1 = Protect) VPP_WD pin
137  0 FlashROM write enable (1 = Enabled)
138 
139 
140 
141  [MAPPERS]
142 
143  - ASCII 8: Common ASC8 mapper
144 
145  - ASCII 16: Common ASC16 mapper
146 
147  - Konami: Common Konami mapper.
148  Bank0 (#4000-#5FFF) can be also changed unless [MAPPER REGISTER] bit 3 is 1
149 
150  - Konami SCC: Common Konami SCC mapper
151 
152  - Linear 64: #0000-#3FFF bank0
153  #4000-#7FFF bank1
154  #8000-#BFFF bank2
155  #C000-#FFFF bank3
156  Banks mapper registers addresses = Konami
157 
158 
159  [DEFAULT VALUES]
160 
161  - MAPPER REGISTER = 0
162  - CONFIG REGISTER = %00000011
163  - MapperBank0 = 0
164  - MapperBank1 = 1
165  - MapperBank2 = 2
166  - MapperBank3 = 3
167  - BankOffset = 0
168  - Subslot register = 0
169 
170 
171  [LOGIC]
172 
173  Bank0 <= "1111111010" when CONFIG REGISTER(4) = '1' and MapperBank0 = "0000000000" else ; DSK mode
174  MapperBank0 + bankOffset;
175 
176  Bank1 <= "1111111011" when CONFIG REGISTER(4) = '1' and MapperBank1 = "0000000001" else ; DSK mode
177  MapperBank1 + bankOffset;
178 
179  Bank2 <= MapperBank2 + bankOffset;
180 
181  Bank3 <= MapperBank3 + bankOffset;
182 
183 
184  RamAdr <=
185  -- Mapper in 64K mode
186  Bank0(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "00" else --#0000-#3FFF
187  Bank1(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "01" else --#4000-#7FFF
188  Bank2(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "10" else --#8000-#BFFF
189  Bank3(8 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "11" else --#C000-#FFFF
190 
191  -- Mapper in SCC, ASC8 or ASC16 modes
192  Bank0(9 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "10" else --#4000-#5FFF
193  Bank1(9 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "11" else --#6000-#7FFF
194  Bank2(9 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "00" else --#8000-#9FFF
195  Bank3(9 downto 0) & adr(12 downto 0); --#A000-#BFFF
196 
197 
198  Note: It is possible to access the whole flashROM from the MegaFlashROM SCC+
199  SD using the offsets register!
200 
201 --------------------------------------------------------------------------------
202 [Subslot 2: 512K RAM expansion]
203 
204  Mapper ports:
205  Page 0 = #FC
206  Page 1 = #FD
207  Page 2 = #FE
208  Page 3 = #FF
209 
210  Default bank values:
211  Page 0 = 3
212  Page 1 = 2
213  Page 2 = 1
214  Page 3 = 0
215 
216  Disabled when [CONFIG REGISTER] bit 5 = 1
217 
218  Since mapper ports must not be read, as stated on MSX Technical Handbook, and
219  mapper ports as read only, as stated on MSX Datapack, all read operations on
220  these ports will not return any value.
221 
222 UPDATE:
223  Initial version indeed did not support reading the memory mapper ports. But
224  upon user request this feature was added later.
225 
226 --------------------------------------------------------------------------------
227 [Subslot 3: MegaSD]
228 
229  Mapper type: ASCII8
230 
231  Default mapper values:
232  Bank0 = 0
233  Bank1 = 1
234  Bank2 = 0
235  Bank3 = 0
236 
237  Memory range 1024K: Banks #00-#7F are mirrored in #80-#FF (except registers
238  bank #40)
239 
240  Memory registers area (Bank #40):
241  #4000-#57FF: SD card access (R/W)
242  #4000-#4FFF: /CS signal = 0 - SD enabled
243  #5000-#5FFF: /CS signal = 1 - SD disabled
244 
245  #5800-#5FFF: SD slot select (bit 0: 0 = SD slot 1, 1 = SD slot 2)
246 
247  Cards work in SPI mode.
248  Signals used: CS, DI, DO, SCLK
249  When reading, 8 bits are read from DO
250  When writing, 8 bits are written to DI
251 
252  SD specifications: https://www.sdcard.org/downloads/pls/simplified_specs/part1_410.pdf
253 
254 ******************************************************************************/
255 
256 constexpr unsigned MEMORY_MAPPER_SIZE = 512;
257 constexpr unsigned MEMORY_MAPPER_MASK = (MEMORY_MAPPER_SIZE / 16) - 1;
258 
259 namespace openmsx {
260 
261 static std::vector<AmdFlash::SectorInfo> getSectorInfo()
262 {
263  std::vector<AmdFlash::SectorInfo> sectorInfo;
264  // 8 * 8kB
265  sectorInfo.insert(end(sectorInfo), 8, {8 * 1024, false});
266  // 127 * 64kB
267  sectorInfo.insert(end(sectorInfo), 127, {64 * 1024, false});
268  return sectorInfo;
269 }
270 
272  : MSXDevice(config)
273  , flash("MFR SCC+ SD flash", getSectorInfo(), 0x207E, true, config)
274  , scc("MFR SCC+ SD SCC-I", config, getCurrentTime(), SCC::SCC_Compatible)
275  , psg("MFR SCC+ SD PSG", DummyAY8910Periphery::instance(), config,
276  getCurrentTime())
277  , configReg(3) // avoid UMR
278  , checkedRam(config.getChildDataAsBool("hasmemorymapper", true) ?
279  std::make_unique<CheckedRam>(config, getName() + " memory mapper", "memory mapper", MEMORY_MAPPER_SIZE * 1024)
280  : nullptr)
281  , mapperIO(checkedRam ? std::make_unique<MapperIO>(*this) : nullptr) // handles ports 0xfc-0xff
282 {
284 
285  getCPUInterface().register_IO_Out(0x10, this);
286  getCPUInterface().register_IO_Out(0x11, this);
287 
288  sdCard[0] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild("sdcard1")));
289  sdCard[1] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild("sdcard2")));
290 }
291 
293 {
294  // unregister extra PSG I/O ports
295  updateConfigReg(3);
296 
297  getCPUInterface().unregister_IO_Out(0x10, this);
298  getCPUInterface().unregister_IO_Out(0x11, this);
299 }
300 
301 void MegaFlashRomSCCPlusSD::powerUp(EmuTime::param time)
302 {
303  scc.powerUp(time);
304  reset(time);
305 }
306 
307 void MegaFlashRomSCCPlusSD::reset(EmuTime::param time)
308 {
309  mapperReg = 0;
310  offsetReg = 0;
311  updateConfigReg(3);
312  subslotReg = 0;
313  for (int bank = 0; bank < 4; ++bank) {
314  bankRegsSubSlot1[bank] = bank;
315  }
316 
317  sccMode = 0;
318  for (int i = 0; i < 4; ++i) {
319  sccBanks[i] = i;
320  }
321  scc.reset(time);
322 
323  psgLatch = 0;
324  psg.reset(time);
325 
326  flash.reset();
327 
328  // memory mapper
329  for (auto i = 0; i < 4; ++i) {
330  memMapperRegs[i] = 3 - i;
331  }
332 
333  for (int bank = 0; bank < 4; ++bank) {
334  bankRegsSubSlot3[bank] = (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 (int i = 0; i < 4; ++i) {
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 (ar.isLoader()) {
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
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:208
constexpr unsigned MEMORY_MAPPER_MASK
void setChipMode(ChipMode newMode)
Definition: SCC.cc:182
byte read(unsigned address)
Definition: AmdFlash.cc:252
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:289
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.
const byte * getReadCacheLine(unsigned address) const
Definition: AmdFlash.cc:258
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
STL namespace.
void reset(EmuTime::param time)
Definition: SCC.cc:172
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
Definition: AmdFlash.hh:55
constexpr unsigned HIGH
Definition: CacheLine.hh:10
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
size_t size(std::string_view utf8)
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:61
MegaFlashRomSCCPlusSD(const DeviceConfig &config)
byte peek(unsigned address) const
Definition: AmdFlash.cc:215
This class keeps track of which bytes in the Ram have been written to.
Definition: CheckedRam.hh:27
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
byte readMem(byte address, EmuTime::param time)
Definition: SCC.cc:192
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:292
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
void reset(EmuTime::param time) override
This method is called on reset.
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:130
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
byte peekMem(byte address, EmuTime::param time) const
Definition: SCC.cc:205
void unregister_IO_Out(byte port, MSXDevice *device)
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:293
void write(unsigned address, byte value)
Definition: AmdFlash.cc:270
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
constexpr nibble mask[4][13]
Definition: RP5C01.cc:33
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:589
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing...
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:138
virtual byte peekIO(word port, EmuTime::param time) const
Read a byte from a given IO port.
Definition: MSXDevice.cc:417
void powerUp(EmuTime::param time)
Definition: SCC.cc:140
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
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.
void reset(EmuTime::param time)
Definition: AY8910.cc:537
constexpr unsigned MEMORY_MAPPER_SIZE
void serialize(Archive &ar, unsigned version)
void writeRegister(unsigned reg, byte value, EmuTime::param time)
Definition: AY8910.cc:594
#define UNREACHABLE
Definition: unreachable.hh:38