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