265 static constexpr
auto sectorInfo = [] {
267 using Info = AmdFlash::SectorInfo;
268 std::array<Info, 8 + 127> result = {};
269 cstd::fill(result.begin(), result.begin() + 8,
Info{ 8 * 1024, false});
270 cstd::fill(result.begin() + 8, result.end(),
Info{64 * 1024, false});
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)
283 , checkedRam(config.getChildDataAsBool(
"hasmemorymapper", true) ?
286 , mapperIO(checkedRam ? std::make_unique<MapperIO>(*this) : nullptr)
330 for (
auto [i, mr] :
enumerate(memMapperRegs)) {
334 for (
auto [bank, reg] :
enumerate(bankRegsSubSlot3)) {
335 reg = (bank == 1) ? 1 : 0;
343 byte MegaFlashRomSCCPlusSD::getSubSlot(
unsigned addr)
const
345 return isSlotExpanderEnabled() ?
346 (subslotReg >> (2 * (addr >> 14))) & 3 : 1;
349 void MegaFlashRomSCCPlusSD::writeToFlash(
unsigned addr,
byte value)
351 if (isFlashRomWriteEnabled()) {
352 flash.
write(addr, value);
361 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
363 return subslotReg ^ 0xFF;
366 switch (getSubSlot(addr)) {
367 case 0:
return peekMemSubSlot0(addr);
368 case 1:
return peekMemSubSlot1(addr, time);
369 case 2:
return isMemoryMapperEnabled() ?
370 peekMemSubSlot2(addr) : 0xFF;
371 case 3:
return peekMemSubSlot3(addr, time);
378 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
380 return subslotReg ^ 0xFF;
383 switch (getSubSlot(addr)) {
384 case 0:
return readMemSubSlot0(addr);
385 case 1:
return readMemSubSlot1(addr, time);
386 case 2:
return isMemoryMapperEnabled() ?
387 readMemSubSlot2(addr) : 0xFF;
388 case 3:
return readMemSubSlot3(addr, time);
395 if (isSlotExpanderEnabled() &&
401 switch (getSubSlot(addr)) {
402 case 0:
return getReadCacheLineSubSlot0(addr);
403 case 1:
return getReadCacheLineSubSlot1(addr);
404 case 2:
return isMemoryMapperEnabled() ?
406 case 3:
return getReadCacheLineSubSlot3(addr);
413 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
415 byte diff = value ^ subslotReg;
417 for (
auto i :
xrange(4)) {
418 if (diff & (3 << (2 * i))) {
424 switch (getSubSlot(addr)) {
425 case 0: writeMemSubSlot0(addr, value);
break;
426 case 1: writeMemSubSlot1(addr, value, time);
break;
427 case 2:
if (isMemoryMapperEnabled()) {
428 writeMemSubSlot2(addr, value);
431 case 3: writeMemSubSlot3(addr, value, time);
break;
438 if (isSlotExpanderEnabled() &&
444 switch (getSubSlot(addr)) {
445 case 0:
return getWriteCacheLineSubSlot0(addr);
446 case 1:
return getWriteCacheLineSubSlot1(addr);
447 case 2:
return isMemoryMapperEnabled() ?
449 case 3:
return getWriteCacheLineSubSlot3(addr);
456 byte MegaFlashRomSCCPlusSD::readMemSubSlot0(
word addr)
460 return flash.
read(addr & 0x3FFF);
463 byte MegaFlashRomSCCPlusSD::peekMemSubSlot0(
word addr)
const
467 return flash.
peek(addr & 0x3FFF);
470 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot0(
word addr)
const
475 void MegaFlashRomSCCPlusSD::writeMemSubSlot0(
word addr,
byte value)
478 writeToFlash(addr & 0x3FFF, value);
481 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot0(
word )
const
488 void MegaFlashRomSCCPlusSD::updateConfigReg(
byte value)
490 if ((value ^ configReg) & 0x08) {
504 MegaFlashRomSCCPlusSD::SCCEnable MegaFlashRomSCCPlusSD::getSCCEnable()
const
506 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
508 }
else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
515 unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot1(
unsigned addr)
const
517 unsigned page = is64KmapperConfigured() ? (addr >> 14) : ((addr >> 13) - 2);
518 unsigned size = is64KmapperConfigured() ? 0x4000 : 0x2000;
520 if (page >= 4)
return unsigned(-1);
522 unsigned bank = bankRegsSubSlot1[page];
523 if (isDSKmodeEnabled() && (page == 0) && (bank == 0)) {
525 }
else if (isDSKmodeEnabled() && (page == 1) && (bank == 1)) {
531 unsigned tmp = (bank *
size) + (addr & (
size - 1));
532 return (tmp + 0x010000) & 0x7FFFFF;
535 byte MegaFlashRomSCCPlusSD::readMemSubSlot1(
word addr, EmuTime::param time)
537 if (isKonamiSCCmapperConfigured()) {
538 SCCEnable enable = getSCCEnable();
539 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
540 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
541 byte val = scc.
readMem(addr & 0xFF, time);
546 unsigned flashAddr = getFlashAddrSubSlot1(addr);
547 return (flashAddr !=
unsigned(-1))
548 ? flash.
read(flashAddr)
552 byte MegaFlashRomSCCPlusSD::peekMemSubSlot1(
word addr, EmuTime::param time)
const
554 if (isKonamiSCCmapperConfigured()) {
555 SCCEnable enable = getSCCEnable();
556 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
557 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
558 byte val = scc.
peekMem(addr & 0xFF, time);
563 unsigned flashAddr = getFlashAddrSubSlot1(addr);
564 return (flashAddr !=
unsigned(-1))
565 ? flash.
peek(flashAddr)
569 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot1(
word addr)
const
571 if (isKonamiSCCmapperConfigured()) {
572 SCCEnable enable = getSCCEnable();
573 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
574 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
579 unsigned flashAddr = getFlashAddrSubSlot1(addr);
580 return (flashAddr !=
unsigned(-1))
585 void MegaFlashRomSCCPlusSD::writeMemSubSlot1(
word addr,
byte value, EmuTime::param time)
588 unsigned flashAddr = getFlashAddrSubSlot1(addr);
597 if (!isConfigRegDisabled() && (addr == 0x7FFC)) {
599 updateConfigReg(value);
602 if (!isMapperRegisterDisabled() && (addr == 0x7FFF)) {
608 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
610 offsetReg = (offsetReg & 0x300) | value;
614 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
616 offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
620 if (isKonamiSCCmapperConfigured()) {
622 if ((addr & 0xFFFE) == 0xBFFE) {
629 SCCEnable enable = getSCCEnable();
630 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
631 ((sccMode & 0x10) == 0x10);
632 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
633 if (((enable == EN_SCC) && !isRamSegment2 &&
634 (0x9800 <= addr) && (addr < 0xA000)) ||
635 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
636 (0xB800 <= addr) && (addr < 0xC000))) {
637 scc.
writeMem(addr & 0xFF, value, time);
642 unsigned page8kB = (addr >> 13) - 2;
643 if (!areBankRegsAndOffsetRegsDisabled() && (page8kB < 4)) {
645 switch (mapperReg & 0xE0) {
648 if ((addr & 0x1800) == 0x1000) {
652 sccBanks[page8kB] = value;
655 byte mask = areKonamiMapperLimitsEnabled() ? 0x3F : 0xFF;
656 bankRegsSubSlot1[page8kB] = value &
mask;
662 if (isWritingKonamiBankRegisterDisabled() && (addr < 0x6000)) {
671 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000)))
break;
672 byte mask = areKonamiMapperLimitsEnabled() ? 0x1F : 0xFF;
673 bankRegsSubSlot1[page8kB] = value &
mask;
680 bankRegsSubSlot1[page8kB] = value;
686 if ((0x6000 <= addr) && (addr < 0x8000)) {
687 byte bank = (addr >> 11) & 0x03;
688 bankRegsSubSlot1[bank] = value;
701 if ((0x6000 <= addr) && (addr < 0x6800)) {
702 bankRegsSubSlot1[0] = 2 * value + 0;
703 bankRegsSubSlot1[1] = 2 * value + 1;
706 if ((0x7000 <= addr) && (addr < 0x7800)) {
707 bankRegsSubSlot1[2] = 2 * value + 0;
708 bankRegsSubSlot1[3] = 2 * value + 1;
715 if (flashAddr !=
unsigned(-1)) {
716 writeToFlash(flashAddr, value);
720 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(
word )
const
727 unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(
word address)
const
729 unsigned bank = memMapperRegs[address >> 14];
733 byte MegaFlashRomSCCPlusSD::readMemSubSlot2(
word addr)
736 return checkedRam->read(calcMemMapperAddress(addr));
739 byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(
word addr)
const
741 return checkedRam->peek(calcMemMapperAddress(addr));
744 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(
word addr)
const
746 return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
749 void MegaFlashRomSCCPlusSD::writeMemSubSlot2(
word addr,
byte value)
752 checkedRam->write(calcMemMapperAddress(addr), value);
755 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(
word addr)
const
757 return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
760 byte MegaFlashRomSCCPlusSD::MapperIO::readIO(
word port, EmuTime::param time)
762 return peekIO(port, time);
765 byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(
word port, EmuTime::param )
const
770 void MegaFlashRomSCCPlusSD::MapperIO::writeIO(
word port,
byte value, EmuTime::param )
773 mega.invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
776 byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(
byte page)
const
778 return mega.memMapperRegs[page];
783 unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(
unsigned addr)
const
785 unsigned page8kB = (addr >> 13) - 2;
786 return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
789 byte MegaFlashRomSCCPlusSD::readMemSubSlot3(
word addr, EmuTime::param )
791 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
793 return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
796 if ((0x4000 <= addr) && (addr < 0xC000)) {
798 unsigned flashAddr = getFlashAddrSubSlot3(addr);
799 return flash.
read(flashAddr);
806 byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(
word addr, EmuTime::param )
const
808 if ((0x4000 <= addr) && (addr < 0xC000)) {
810 unsigned flashAddr = getFlashAddrSubSlot3(addr);
811 return flash.
peek(flashAddr);
818 const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(
word addr)
const
820 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
824 if ((0x4000 <= addr) && (addr < 0xC000)) {
826 unsigned flashAddr = getFlashAddrSubSlot3(addr);
833 void MegaFlashRomSCCPlusSD::writeMemSubSlot3(
word addr,
byte value, EmuTime::param )
836 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
837 if (addr >= 0x5800) {
838 selectedCard = value & 1;
841 sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0);
846 if ((0x4000 <= addr) && (addr < 0xC000)) {
847 unsigned flashAddr = getFlashAddrSubSlot3(addr);
848 writeToFlash(flashAddr, value);
852 if ((0x6000 <= addr) && (addr < 0x8000)) {
853 byte page8kB = (addr >> 11) & 0x03;
854 bankRegsSubSlot3[page8kB] = value;
859 byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(
word )
const
868 switch (port & 0xFF) {
870 if (!isPSGalsoMappedToNormalPorts())
return;
873 psgLatch = value & 0x0F;
877 if (!isPSGalsoMappedToNormalPorts())
return;
888 template<
typename Archive>
892 ar.template serializeBase<MSXDevice>(*
this);
895 ar.serialize(
"flash", flash,
896 "subslotReg", subslotReg);
902 ar.serialize(
"scc", scc,
904 "sccBanks", sccBanks,
906 "psgLatch", psgLatch,
907 "configReg", configReg,
908 "mapperReg", mapperReg,
909 "offsetReg", offsetReg,
910 "bankRegsSubSlot1", bankRegsSubSlot1);
911 if constexpr (Archive::IS_LOADER) {
913 byte tmp = configReg;
915 updateConfigReg(tmp);
920 if (checkedRam) ar.serialize(
"ram", checkedRam->getUncheckedRam());
921 ar.serialize(
"memMapperRegs", memMapperRegs);
924 ar.serialize(
"bankRegsSubSlot3", bankRegsSubSlot3,
925 "selectedCard", selectedCard,
926 "sdCard0", *sdCard[0],
927 "sdCard1", *sdCard[1]);
constexpr unsigned MEMORY_MAPPER_MASK
constexpr unsigned MEMORY_MAPPER_SIZE
void reset(EmuTime::param time)
void writeRegister(unsigned reg, byte value, EmuTime::param time)
void write(unsigned address, byte value)
byte peek(unsigned address) const
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
byte read(unsigned address) const
const byte * getReadCacheLine(unsigned address) const
This class keeps track of which bytes in the Ram have been written to.
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.
static byte unmappedRead[0x10000]
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
EmuTime::param getCurrentTime() const
static byte unmappedWrite[0x10000]
MSXCPUInterface & getCPUInterface() const
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.
~MegaFlashRomSCCPlusSD() override
void writeMem(byte address, byte value, EmuTime::param time)
void setChipMode(ChipMode newMode)
void powerUp(EmuTime::param time)
byte readMem(byte address, EmuTime::param time)
void reset(EmuTime::param time)
byte peekMem(byte address, EmuTime::param time) const
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
constexpr void fill(ForwardIt first, ForwardIt last, const T &value)
std::string getName(KeyCode keyCode)
Translate key code to key name.
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
AmdFlash::SectorInfo Info
uint16_t word
16 bit unsigned integer
constexpr nibble mask[4][13]
constexpr void iota(ForwardIt first, ForwardIt last, T value)
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)