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