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 for (auto port : {0x10, 0x11}) {
289 getCPUInterface().register_IO_Out(narrow_cast<byte>(port), this);
290 }
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 for (auto port : {0x10, 0x11}) {
301 getCPUInterface().unregister_IO_Out(narrow_cast<byte>(port), this);
302 }
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;
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;
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;
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;
450 }
451}
452
454
455byte MegaFlashRomSCCPlusSD::readMemSubSlot0(word addr) const
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 for (auto port : {0xa0, 0xa1}) {
492 getCPUInterface().register_IO_Out(narrow_cast<byte>(port), this);
493 }
494 } else {
495 for (auto port : {0xa0, 0xa1}) {
496 getCPUInterface().unregister_IO_Out(narrow_cast<byte>(port), this);
497 }
498 }
499 }
500 configReg = value;
501 flash.setVppWpPinLow(isFlashRomBlockProtectEnabled());
502 invalidateDeviceRWCache(); // flush all to be sure
503}
504
505MegaFlashRomSCCPlusSD::SCCEnable MegaFlashRomSCCPlusSD::getSCCEnable() const
506{
507 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
508 return EN_SCCPLUS;
509 } else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
510 return EN_SCC;
511 } else {
512 return EN_NONE;
513 }
514}
515
516unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot1(unsigned addr) const
517{
518 unsigned page = is64KmapperConfigured() ? (addr >> 14) : ((addr >> 13) - 2);
519 unsigned size = is64KmapperConfigured() ? 0x4000 : 0x2000;
520
521 if (page >= 4) return unsigned(-1); // outside [0x4000, 0xBFFF] for non-64K mapper
522
523 unsigned bank = bankRegsSubSlot1[page];
524 if (isDSKmodeEnabled() && (page == 0) && (bank == 0)) {
525 bank = 0x3FA;
526 } else if (isDSKmodeEnabled() && (page == 1) && (bank == 1)) {
527 bank = 0x3FB;
528 } else { // not DSK mode
529 bank += offsetReg;
530 }
531
532 unsigned tmp = (bank * size) + (addr & (size - 1));
533 return (tmp + 0x010000) & 0x7FFFFF; // wrap at 8MB
534}
535
536byte MegaFlashRomSCCPlusSD::readMemSubSlot1(word addr, EmuTime::param time)
537{
538 if (isKonamiSCCmapperConfigured()) { // Konami SCC
539 SCCEnable enable = getSCCEnable();
540 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
541 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
542 byte val = scc.readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
543 return val;
544 }
545 }
546
547 unsigned flashAddr = getFlashAddrSubSlot1(addr);
548 return (flashAddr != unsigned(-1))
549 ? flash.read(flashAddr)
550 : 0xFF; // unmapped read
551}
552
553byte MegaFlashRomSCCPlusSD::peekMemSubSlot1(word addr, EmuTime::param time) const
554{
555 if (isKonamiSCCmapperConfigured()) { // Konami SCC
556 SCCEnable enable = getSCCEnable();
557 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
558 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
559 byte val = scc.peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
560 return val;
561 }
562 }
563
564 unsigned flashAddr = getFlashAddrSubSlot1(addr);
565 return (flashAddr != unsigned(-1))
566 ? flash.peek(flashAddr)
567 : 0xFF; // unmapped read
568}
569
570const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot1(word addr) const
571{
572 if (isKonamiSCCmapperConfigured()) {
573 SCCEnable enable = getSCCEnable();
574 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
575 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
576 return nullptr;
577 }
578 }
579
580 unsigned flashAddr = getFlashAddrSubSlot1(addr);
581 return (flashAddr != unsigned(-1))
582 ? flash.getReadCacheLine(flashAddr)
583 : unmappedRead.data();
584}
585
586void MegaFlashRomSCCPlusSD::writeMemSubSlot1(word addr, byte value, EmuTime::param time)
587{
588 // address is calculated before writes to other regions take effect
589 unsigned flashAddr = getFlashAddrSubSlot1(addr);
590
591 // There are several overlapping functional regions in the address
592 // space. A single write can trigger behaviour in multiple regions. In
593 // other words there's no priority amongst the regions where a higher
594 // priority region blocks the write from the lower priority regions.
595 // This only goes for places where the flash is 'seen', so not for the
596 // SCC registers and the SSR
597
598 if (!isConfigRegDisabled() && (addr == 0x7FFC)) {
599 // write config register
600 updateConfigReg(value);
601 }
602
603 if (!isMapperRegisterDisabled() && (addr == 0x7FFF)) {
604 // write mapper register
605 mapperReg = value;
606 invalidateDeviceRWCache(); // flush all to be sure
607 }
608
609 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
610 // write offset register low part
611 offsetReg = (offsetReg & 0x300) | value;
613 }
614
615 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
616 // write offset register high part (bit 8 and 9)
617 offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
619 }
620
621 if (isKonamiSCCmapperConfigured()) {
622 // Konami-SCC
623 if ((addr & 0xFFFE) == 0xBFFE) {
624 sccMode = value;
625 scc.setChipMode((value & 0x20) ? SCC::SCC_plusmode
626 : SCC::SCC_Compatible);
627 invalidateDeviceRWCache(0x9800, 0x800);
628 invalidateDeviceRWCache(0xB800, 0x800);
629 }
630 SCCEnable enable = getSCCEnable();
631 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
632 ((sccMode & 0x10) == 0x10);
633 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
634 if (((enable == EN_SCC) && !isRamSegment2 &&
635 (0x9800 <= addr) && (addr < 0xA000)) ||
636 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
637 (0xB800 <= addr) && (addr < 0xC000))) {
638 scc.writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
639 return; // Pazos: when SCC registers are selected flashROM is not seen, so it does not accept commands.
640 }
641 }
642
643 unsigned page8kB = (addr >> 13) - 2;
644 if (!areBankRegsAndOffsetRegsDisabled() && (page8kB < 4)) {
645 // (possibly) write to bank registers
646 switch (mapperReg & 0xE0) {
647 case 0x00:
648 // Konami-SCC
649 if ((addr & 0x1800) == 0x1000) {
650 // Storing 'sccBanks' may seem redundant at
651 // first, but it's required to calculate
652 // whether the SCC is enabled or not.
653 sccBanks[page8kB] = value;
654 // Masking of the mapper bits is done on
655 // write (and only in Konami(-scc) mode)
656 byte mask = areKonamiMapperLimitsEnabled() ? 0x3F : 0xFF;
657 bankRegsSubSlot1[page8kB] = value & mask;
658 invalidateDeviceRWCache(0x4000 + 0x2000 * page8kB, 0x2000);
659 }
660 break;
661 case 0x20: {
662 // Konami
663 if (isWritingKonamiBankRegisterDisabled() && (addr < 0x6000)) {
664 // Switching 0x4000-0x5FFF disabled.
665 // This bit blocks writing to the bank register
666 // (an alternative was forcing a 0 on read).
667 // It only has effect in Konami mode.
668 break;
669 }
670 // Making of the mapper bits is done on
671 // write (and only in Konami(-scc) mode)
672 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000))) break; // only SCC range works
673 byte mask = areKonamiMapperLimitsEnabled() ? 0x1F : 0xFF;
674 bankRegsSubSlot1[page8kB] = value & mask;
675 invalidateDeviceRWCache(0x4000 + 0x2000 * page8kB, 0x2000);
676 break;
677 }
678 case 0x40:
679 case 0x60:
680 // 64kB
681 bankRegsSubSlot1[page8kB] = value;
682 invalidateDeviceRWCache(0x0000 + 0x4000 * page8kB, 0x4000);
683 break;
684 case 0x80:
685 case 0xA0:
686 // ASCII-8
687 if ((0x6000 <= addr) && (addr < 0x8000)) {
688 byte bank = (addr >> 11) & 0x03;
689 bankRegsSubSlot1[bank] = value;
690 invalidateDeviceRWCache(0x4000 + 0x2000 * bank, 0x2000);
691 }
692 break;
693 case 0xC0:
694 case 0xE0:
695 // ASCII-16
696 // This behaviour is confirmed by Manuel Pazos (creator
697 // of the cartridge): ASCII-16 uses all 4 bank registers
698 // and one bank switch changes 2 registers at once.
699 // This matters when switching mapper mode, because
700 // the content of the bank registers is unchanged after
701 // a switch.
702 if ((0x6000 <= addr) && (addr < 0x6800)) {
703 bankRegsSubSlot1[0] = narrow_cast<uint8_t>(2 * value + 0);
704 bankRegsSubSlot1[1] = narrow_cast<uint8_t>(2 * value + 1);
705 invalidateDeviceRWCache(0x4000, 0x4000);
706 }
707 if ((0x7000 <= addr) && (addr < 0x7800)) {
708 bankRegsSubSlot1[2] = narrow_cast<uint8_t>(2 * value + 0);
709 bankRegsSubSlot1[3] = narrow_cast<uint8_t>(2 * value + 1);
710 invalidateDeviceRWCache(0x8000, 0x4000);
711 }
712 break;
713 }
714 }
715
716 if (flashAddr != unsigned(-1)) {
717 writeToFlash(flashAddr, value);
718 }
719}
720
721byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(word /*addr*/) const
722{
723 return nullptr; // flash isn't cacheable
724}
725
727
728unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(word address) const
729{
730 auto bank = memMapperRegs[address >> 14];
731 return ((bank & MEMORY_MAPPER_MASK) << 14) | (address & 0x3FFF);
732}
733
734byte MegaFlashRomSCCPlusSD::readMemSubSlot2(word addr)
735{
736 // read from the memory mapper
737 return checkedRam->read(calcMemMapperAddress(addr));
738}
739
740byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(word addr) const
741{
742 return checkedRam->peek(calcMemMapperAddress(addr));
743}
744
745const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(word addr) const
746{
747 return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
748}
749
750void MegaFlashRomSCCPlusSD::writeMemSubSlot2(word addr, byte value)
751{
752 // write to the memory mapper
753 checkedRam->write(calcMemMapperAddress(addr), value);
754}
755
756byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(word addr) const
757{
758 return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
759}
760
761byte MegaFlashRomSCCPlusSD::MapperIO::readIO(word port, EmuTime::param time)
762{
763 return peekIO(port, time);
764}
765
766byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(word port, EmuTime::param /*time*/) const
767{
768 return getSelectedSegment(port & 3) | byte(~MEMORY_MAPPER_MASK);
769}
770
771void MegaFlashRomSCCPlusSD::MapperIO::writeIO(word port, byte value, EmuTime::param /*time*/)
772{
773 mega.memMapperRegs[port & 3] = value & MEMORY_MAPPER_MASK;
774 mega.invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
775}
776
777byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(byte page) const
778{
779 return mega.memMapperRegs[page];
780}
781
783
784unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(unsigned addr) const
785{
786 unsigned page8kB = (addr >> 13) - 2;
787 return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
788}
789
790byte MegaFlashRomSCCPlusSD::readMemSubSlot3(word addr, EmuTime::param /*time*/)
791{
792 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
793 // transfer from SD card
794 return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
795 }
796
797 if ((0x4000 <= addr) && (addr < 0xC000)) {
798 // read (flash)rom content
799 unsigned flashAddr = getFlashAddrSubSlot3(addr);
800 return flash.read(flashAddr);
801 } else {
802 // unmapped read
803 return 0xFF;
804 }
805}
806
807byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(word addr, EmuTime::param /*time*/) const
808{
809 if ((0x4000 <= addr) && (addr < 0xC000)) {
810 // read (flash)rom content
811 unsigned flashAddr = getFlashAddrSubSlot3(addr);
812 return flash.peek(flashAddr);
813 } else {
814 // unmapped read
815 return 0xFF;
816 }
817}
818
819const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(word addr) const
820{
821 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
822 return nullptr;
823 }
824
825 if ((0x4000 <= addr) && (addr < 0xC000)) {
826 // (flash)rom content
827 unsigned flashAddr = getFlashAddrSubSlot3(addr);
828 return flash.getReadCacheLine(flashAddr);
829 } else {
830 return unmappedRead.data();
831 }
832}
833
834void MegaFlashRomSCCPlusSD::writeMemSubSlot3(word addr, byte value, EmuTime::param /*time*/)
835{
836
837 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
838 if (addr >= 0x5800) {
839 selectedCard = value & 1;
840 } else {
841 // transfer to SD card
842 sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0); // ignore return value
843 }
844 }
845
846 // write to flash (first, before modifying bank regs)
847 if ((0x4000 <= addr) && (addr < 0xC000)) {
848 unsigned flashAddr = getFlashAddrSubSlot3(addr);
849 writeToFlash(flashAddr, value);
850 }
851
852 // ASCII-8 mapper
853 if ((0x6000 <= addr) && (addr < 0x8000)) {
854 byte page8kB = (addr >> 11) & 0x03;
855 bankRegsSubSlot3[page8kB] = value;
856 invalidateDeviceRWCache(0x4000 + 0x2000 * page8kB, 0x2000);
857 }
858}
859
860byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(word /*addr*/) const
861{
862 return nullptr; // flash isn't cacheable
863}
864
866
867void MegaFlashRomSCCPlusSD::writeIO(word port, byte value, EmuTime::param time)
868{
869 switch (port & 0xFF) {
870 case 0xA0:
871 if (!isPSGalsoMappedToNormalPorts()) return;
872 [[fallthrough]];
873 case 0x10:
874 psgLatch = value & 0x0F;
875 break;
876
877 case 0xA1:
878 if (!isPSGalsoMappedToNormalPorts()) return;
879 [[fallthrough]];
880 case 0x11:
881 psg.writeRegister(psgLatch, value, time);
882 break;
883
884 default:
886 }
887}
888
889template<typename Archive>
890void MegaFlashRomSCCPlusSD::serialize(Archive& ar, unsigned /*version*/)
891{
892 // skip MSXRom base class
893 ar.template serializeBase<MSXDevice>(*this);
894
895 // overall
896 ar.serialize("flash", flash,
897 "subslotReg", subslotReg);
898
899 // subslot 0 stuff
900 // (nothing)
901
902 // subslot 1 stuff
903 ar.serialize("scc", scc,
904 "sccMode", sccMode,
905 "sccBanks", sccBanks,
906 "psg", psg,
907 "psgLatch", psgLatch,
908 "configReg", configReg,
909 "mapperReg", mapperReg,
910 "offsetReg", offsetReg,
911 "bankRegsSubSlot1", bankRegsSubSlot1);
912 if constexpr (Archive::IS_LOADER) {
913 // Re-register PSG ports (if needed)
914 byte tmp = configReg;
915 configReg = 3; // set to un-registered
916 updateConfigReg(tmp); // restore correct value
917 }
918
919 // subslot 2 stuff
920 // TODO ar.serialize("checkedRam", checkedRam);
921 if (checkedRam) ar.serialize("ram", checkedRam->getUncheckedRam());
922 ar.serialize("memMapperRegs", memMapperRegs);
923
924 // subslot 3 stuff
925 ar.serialize("bankRegsSubSlot3", bankRegsSubSlot3,
926 "selectedCard", selectedCard,
927 "sdCard0", *sdCard[0],
928 "sdCard1", *sdCard[1]);
929}
932
933} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
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
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.
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
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
AmdFlash::SectorInfo Info
Definition RomManbow2.cc:18
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
constexpr void iota(ForwardIt first, ForwardIt last, T value)
Definition ranges.hh:312
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