openMSX
MegaFlashRomSCCPlusSD.cc
Go to the documentation of this file.
3#include "MSXCPUInterface.hh"
4#include "CacheLine.hh"
5#include "CheckedRam.hh"
6#include "SdCard.hh"
7#include "enumerate.hh"
8#include "narrow.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--------------------------------------------------------------------------------
20MegaFlashROM 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
74by 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 remapped 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
226UPDATE:
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
260static constexpr unsigned MEMORY_MAPPER_SIZE = 512;
261static constexpr uint8_t MEMORY_MAPPER_MASK = (MEMORY_MAPPER_SIZE / 16) - 1;
262
263namespace openmsx {
264
265static constexpr auto sectorInfo = [] {
266 // 8 * 8kB, followed by 127 * 64kB
267 using Info = AmdFlash::SectorInfo;
268 std::array<Info, 8 + 127> result = {};
269 std::fill(result.begin(), result.begin() + 8, Info{ 8 * 1024, false});
270 std::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 , checkedRam(config.getChildDataAsBool("hasmemorymapper", true) ?
283 std::make_unique<CheckedRam>(config, getName() + " memory mapper", "memory mapper", MEMORY_MAPPER_SIZE * 1024)
284 : nullptr)
285 , mapperIO(checkedRam ? std::make_unique<MapperIO>(*this) : nullptr) // handles ports 0xfc-0xff
286{
288
289 getCPUInterface().register_IO_Out(0x10, this);
290 getCPUInterface().register_IO_Out(0x11, this);
291
292 sdCard[0] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild("sdcard1")));
293 sdCard[1] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild("sdcard2")));
294}
295
297{
298 // unregister extra PSG I/O ports
299 updateConfigReg(3);
300
303}
304
305void MegaFlashRomSCCPlusSD::powerUp(EmuTime::param time)
306{
307 scc.powerUp(time);
308 reset(time);
309}
310
311void MegaFlashRomSCCPlusSD::reset(EmuTime::param time)
312{
313 mapperReg = 0;
314 offsetReg = 0;
315 updateConfigReg(3);
316 subslotReg = 0;
317 ranges::iota(bankRegsSubSlot1, byte(0));
318
319 sccMode = 0;
320 ranges::iota(sccBanks, byte(0));
321 scc.reset(time);
322
323 psgLatch = 0;
324 psg.reset(time);
325
326 flash.reset();
327
328 // memory mapper
329 for (auto [i, mr] : enumerate(memMapperRegs)) {
330 mr = byte(3 - i);
331 }
332
333 for (auto [bank, reg] : enumerate(bankRegsSubSlot3)) {
334 reg = (bank == 1) ? 1 : 0;
335 }
336
337 selectedCard = 0;
338
339 invalidateDeviceRWCache(); // flush all to be sure
340}
341
342byte MegaFlashRomSCCPlusSD::getSubSlot(unsigned addr) const
343{
344 return isSlotExpanderEnabled() ?
345 (subslotReg >> (2 * (addr >> 14))) & 3 : 1;
346}
347
348void 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
358byte 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
375byte 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.data();
405 case 3: return getReadCacheLineSubSlot3(addr);
406 default: UNREACHABLE; return nullptr;
407 }
408}
409
410void MegaFlashRomSCCPlusSD::writeMem(word addr, byte value, EmuTime::param time)
411{
412 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
413 // write subslot register
414 byte diff = value ^ subslotReg;
415 subslotReg = value;
416 for (auto i : xrange(4)) {
417 if (diff & (3 << (2 * i))) {
418 invalidateDeviceRWCache(0x4000 * i, 0x4000);
419 }
420 }
421 }
422
423 switch (getSubSlot(addr)) {
424 case 0: writeMemSubSlot0(addr, value); break;
425 case 1: writeMemSubSlot1(addr, value, time); break;
426 case 2: if (isMemoryMapperEnabled()) {
427 writeMemSubSlot2(addr, value);
428 }
429 break;
430 case 3: writeMemSubSlot3(addr, value, time); break;
431 default: UNREACHABLE;
432 }
433}
434
436{
437 if (isSlotExpanderEnabled() &&
438 ((addr & CacheLine::HIGH) == (0xFFFF & CacheLine::HIGH))) {
439 // read subslot register
440 return nullptr;
441 }
442
443 switch (getSubSlot(addr)) {
444 case 0: return getWriteCacheLineSubSlot0(addr);
445 case 1: return getWriteCacheLineSubSlot1(addr);
446 case 2: return isMemoryMapperEnabled() ?
447 getWriteCacheLineSubSlot2(addr) : unmappedWrite.data();
448 case 3: return getWriteCacheLineSubSlot3(addr);
449 default: UNREACHABLE; return nullptr;
450 }
451}
452
454
455byte 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
462byte 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
469const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot0(word addr) const
470{
471 return flash.getReadCacheLine(addr & 0x3FFF);
472}
473
474void 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
480byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot0(word /*addr*/) const
481{
482 return nullptr; // flash isn't cacheable
483}
484
486
487void 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 {
496 }
497 }
498 configReg = value;
499 flash.setVppWpPinLow(isFlashRomBlockProtectEnabled());
500 invalidateDeviceRWCache(); // flush all to be sure
501}
502
503MegaFlashRomSCCPlusSD::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
514unsigned 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
534byte 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(narrow_cast<uint8_t>(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
551byte 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(narrow_cast<uint8_t>(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
568const 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.data();
582}
583
584void 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(narrow_cast<uint8_t>(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] = narrow_cast<uint8_t>(2 * value + 0);
702 bankRegsSubSlot1[1] = narrow_cast<uint8_t>(2 * value + 1);
703 invalidateDeviceRWCache(0x4000, 0x4000);
704 }
705 if ((0x7000 <= addr) && (addr < 0x7800)) {
706 bankRegsSubSlot1[2] = narrow_cast<uint8_t>(2 * value + 0);
707 bankRegsSubSlot1[3] = narrow_cast<uint8_t>(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
719byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(word /*addr*/) const
720{
721 return nullptr; // flash isn't cacheable
722}
723
725
726unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(word address) const
727{
728 auto bank = memMapperRegs[address >> 14];
729 return ((bank & MEMORY_MAPPER_MASK) << 14) | (address & 0x3FFF);
730}
731
732byte MegaFlashRomSCCPlusSD::readMemSubSlot2(word addr)
733{
734 // read from the memory mapper
735 return checkedRam->read(calcMemMapperAddress(addr));
736}
737
738byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(word addr) const
739{
740 return checkedRam->peek(calcMemMapperAddress(addr));
741}
742
743const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(word addr) const
744{
745 return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
746}
747
748void MegaFlashRomSCCPlusSD::writeMemSubSlot2(word addr, byte value)
749{
750 // write to the memory mapper
751 checkedRam->write(calcMemMapperAddress(addr), value);
752}
753
754byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(word addr) const
755{
756 return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
757}
758
759byte MegaFlashRomSCCPlusSD::MapperIO::readIO(word port, EmuTime::param time)
760{
761 return peekIO(port, time);
762}
763
764byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(word port, EmuTime::param /*time*/) const
765{
766 return getSelectedSegment(port & 3) | byte(~MEMORY_MAPPER_MASK);
767}
768
769void 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
775byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(byte page) const
776{
777 return mega.memMapperRegs[page];
778}
779
781
782unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(unsigned addr) const
783{
784 unsigned page8kB = (addr >> 13) - 2;
785 return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
786}
787
788byte 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
805byte 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
817const 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.data();
829 }
830}
831
832void 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
858byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(word /*addr*/) const
859{
860 return nullptr; // flash isn't cacheable
861}
862
864
865void 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:
884 }
885}
886
887template<typename Archive>
888void MegaFlashRomSCCPlusSD::serialize(Archive& ar, unsigned /*version*/)
889{
890 // skip MSXRom base class
891 ar.template serializeBase<MSXDevice>(*this);
892
893 // overall
894 ar.serialize("flash", flash,
895 "subslotReg", subslotReg);
896
897 // subslot 0 stuff
898 // (nothing)
899
900 // subslot 1 stuff
901 ar.serialize("scc", scc,
902 "sccMode", sccMode,
903 "sccBanks", sccBanks,
904 "psg", psg,
905 "psgLatch", psgLatch,
906 "configReg", configReg,
907 "mapperReg", mapperReg,
908 "offsetReg", offsetReg,
909 "bankRegsSubSlot1", bankRegsSubSlot1);
910 if constexpr (Archive::IS_LOADER) {
911 // Re-register PSG ports (if needed)
912 byte tmp = configReg;
913 configReg = 3; // set to un-registered
914 updateConfigReg(tmp); // restore correct value
915 }
916
917 // subslot 2 stuff
918 // TODO ar.serialize("checkedRam", checkedRam);
919 if (checkedRam) ar.serialize("ram", checkedRam->getUncheckedRam());
920 ar.serialize("memMapperRegs", memMapperRegs);
921
922 // subslot 3 stuff
923 ar.serialize("bankRegsSubSlot3", bankRegsSubSlot3,
924 "selectedCard", selectedCard,
925 "sdCard0", *sdCard[0],
926 "sdCard1", *sdCard[1]);
927}
930
931} // namespace openmsx
void reset(EmuTime::param time)
Definition: AY8910.cc:510
void writeRegister(unsigned reg, uint8_t value, EmuTime::param time)
Definition: AY8910.cc:567
void write(size_t address, uint8_t value)
Definition: AmdFlash.cc:265
const uint8_t * getReadCacheLine(size_t address) const
Definition: AmdFlash.cc:254
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
Definition: AmdFlash.hh:65
uint8_t peek(size_t address) const
Definition: AmdFlash.cc:212
uint8_t read(size_t address) const
Definition: AmdFlash.cc:248
This class keeps track of which bytes in the Ram have been written to.
Definition: CheckedRam.hh:28
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:66
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void unregister_IO_Out(byte port, MSXDevice *device)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:36
static std::array< byte, 0x10000 > unmappedRead
Definition: MSXDevice.hh:304
static std::array< byte, 0x10000 > unmappedWrite
Definition: MSXDevice.hh:305
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:212
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:125
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:133
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 setChipMode(ChipMode newMode)
Definition: SCC.cc:183
void powerUp(EmuTime::param time)
Definition: SCC.cc:141
@ SCC_plusmode
Definition: SCC.hh:16
@ SCC_Compatible
Definition: SCC.hh:16
uint8_t readMem(uint8_t address, EmuTime::param time)
Definition: SCC.cc:193
void reset(EmuTime::param time)
Definition: SCC.cc:173
uint8_t peekMem(uint8_t address, EmuTime::param time) const
Definition: SCC.cc:206
void writeMem(uint8_t address, uint8_t value, EmuTime::param time)
Definition: SCC.cc:285
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
constexpr unsigned HIGH
Definition: CacheLine.hh:10
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:730
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
AmdFlash::SectorInfo Info
Definition: RomManbow2.cc:18
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:287
constexpr void iota(ForwardIt first, ForwardIt last, T value)
Definition: ranges.hh:294
STL namespace.
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:132