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 static const unsigned MEMORY_MAPPER_SIZE = 512;
257 static const 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  invalidateMemCache(0x0000, 0x10000); // 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  invalidateMemCache(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  invalidateMemCache(0x0000, 0x10000); // 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  invalidateMemCache(0x0000, 0x10000); // flush all to be sure
605  }
606 
607  if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
608  // write offset register low part
609  offsetReg = (offsetReg & 0x300) | value;
610  invalidateMemCache(0x0000, 0x10000);
611  }
612 
613  if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
614  // write offset register high part (bit 8 and 9)
615  offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
616  invalidateMemCache(0x0000, 0x10000);
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  invalidateMemCache(0x9800, 0x800);
626  invalidateMemCache(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  invalidateMemCache(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  invalidateMemCache(0x4000 + 0x2000 * page8kB, 0x2000);
674  break;
675  }
676  case 0x40:
677  case 0x60:
678  // 64kB
679  bankRegsSubSlot1[page8kB] = value;
680  invalidateMemCache(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  invalidateMemCache(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  invalidateMemCache(0x4000, 0x4000);
704  }
705  if ((0x7000 <= addr) && (addr < 0x7800)) {
706  bankRegsSubSlot1[2] = 2 * value + 0;
707  bankRegsSubSlot1[3] = 2 * value + 1;
708  invalidateMemCache(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 }
773 
774 byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(byte page) const
775 {
776  return mega.memMapperRegs[page];
777 }
778 
780 
781 unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(unsigned addr) const
782 {
783  unsigned page8kB = (addr >> 13) - 2;
784  return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
785 }
786 
787 byte MegaFlashRomSCCPlusSD::readMemSubSlot3(word addr, EmuTime::param /*time*/)
788 {
789  if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
790  // transfer from SD card
791  return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
792  }
793 
794  if ((0x4000 <= addr) && (addr < 0xC000)) {
795  // read (flash)rom content
796  unsigned flashAddr = getFlashAddrSubSlot3(addr);
797  return flash.read(flashAddr);
798  } else {
799  // unmapped read
800  return 0xFF;
801  }
802 }
803 
804 byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(word addr, EmuTime::param /*time*/) const
805 {
806  if ((0x4000 <= addr) && (addr < 0xC000)) {
807  // read (flash)rom content
808  unsigned flashAddr = getFlashAddrSubSlot3(addr);
809  return flash.peek(flashAddr);
810  } else {
811  // unmapped read
812  return 0xFF;
813  }
814 }
815 
816 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(word addr) const
817 {
818  if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
819  return nullptr;
820  }
821 
822  if ((0x4000 <= addr) && (addr < 0xC000)) {
823  // (flash)rom content
824  unsigned flashAddr = getFlashAddrSubSlot3(addr);
825  return flash.getReadCacheLine(flashAddr);
826  } else {
827  return unmappedRead;
828  }
829 }
830 
831 void MegaFlashRomSCCPlusSD::writeMemSubSlot3(word addr, byte value, EmuTime::param /*time*/)
832 {
833 
834  if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
835  if (addr >= 0x5800) {
836  selectedCard = value & 1;
837  } else {
838  // transfer to SD card
839  sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0); // ignore return value
840  }
841  }
842 
843  // write to flash (first, before modifying bank regs)
844  if ((0x4000 <= addr) && (addr < 0xC000)) {
845  unsigned flashAddr = getFlashAddrSubSlot3(addr);
846  writeToFlash(flashAddr, value);
847  }
848 
849  // ASCII-8 mapper
850  if ((0x6000 <= addr) && (addr < 0x8000)) {
851  byte page8kB = (addr >> 11) & 0x03;
852  bankRegsSubSlot3[page8kB] = value;
853  invalidateMemCache(0x4000 + 0x2000 * page8kB, 0x2000);
854  }
855 }
856 
857 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(word /*addr*/) const
858 {
859  return nullptr; // flash isn't cacheable
860 }
861 
863 
864 void MegaFlashRomSCCPlusSD::writeIO(word port, byte value, EmuTime::param time)
865 {
866  switch (port & 0xFF) {
867  case 0xA0:
868  if (!isPSGalsoMappedToNormalPorts()) return;
869  // fall-through
870  case 0x10:
871  psgLatch = value & 0x0F;
872  break;
873 
874  case 0xA1:
875  if (!isPSGalsoMappedToNormalPorts()) return;
876  // fall-through
877  case 0x11:
878  psg.writeRegister(psgLatch, value, time);
879  break;
880 
881  default:
882  UNREACHABLE;
883  }
884 }
885 
886 template<typename Archive>
887 void MegaFlashRomSCCPlusSD::serialize(Archive& ar, unsigned /*version*/)
888 {
889  // skip MSXRom base class
890  ar.template serializeBase<MSXDevice>(*this);
891 
892  // overall
893  ar.serialize("flash", flash,
894  "subslotReg", subslotReg);
895 
896  // subslot 0 stuff
897  // (nothing)
898 
899  // subslot 1 stuff
900  ar.serialize("scc", scc,
901  "sccMode", sccMode,
902  "sccBanks", sccBanks,
903  "psg", psg,
904  "psgLatch", psgLatch,
905  "configReg", configReg,
906  "mapperReg", mapperReg,
907  "offsetReg", offsetReg,
908  "bankRegsSubSlot1", bankRegsSubSlot1);
909  if (ar.isLoader()) {
910  // Re-register PSG ports (if needed)
911  byte tmp = configReg;
912  configReg = 3; // set to un-registered
913  updateConfigReg(tmp); // restore correct value
914  }
915 
916  // subslot 2 stuff
917  // TODO ar.serialize("checkedRam", checkedRam);
918  if (checkedRam) ar.serialize("ram", checkedRam->getUncheckedRam());
919  ar.serialize("memMapperRegs", memMapperRegs);
920 
921  // subslot 3 stuff
922  ar.serialize("bankRegsSubSlot3", bankRegsSubSlot3,
923  "selectedCard", selectedCard,
924  "sdCard0", *sdCard[0],
925  "sdCard1", *sdCard[1]);
926 }
928 REGISTER_MSXDEVICE(MegaFlashRomSCCPlusSD, "MegaFlashRomSCCPlusSD");
929 
930 } // namespace openmsx
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
const XMLElement * findChild(string_view name) const
Definition: DeviceConfig.cc:61
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
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
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
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:133
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 unmappedRead[0x10000]
Definition: MSXDevice.hh:274
void write(unsigned address, byte value)
Definition: AmdFlash.cc:270
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1006
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:275
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:141
virtual byte peekIO(word port, EmuTime::param time) const
Read a byte from a given IO port.
Definition: MSXDevice.cc:407
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.
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.hh:62
void reset(EmuTime::param time)
Definition: AY8910.cc:537
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:458
auto end(const string_view &x)
Definition: string_view.hh:152
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