263static constexpr unsigned MEMORY_MAPPER_SIZE = 512;
264static constexpr uint8_t MEMORY_MAPPER_MASK = (MEMORY_MAPPER_SIZE / 16) - 1;
270 , flash(
"MFR SCC+ SD flash", AmdFlashChip::M29W640GB, {}, config)
274 , checkedRam(config.getChildDataAsBool(
"hasmemorymapper",
true) ?
275 std::make_unique<CheckedRam>(config, getName() +
" memory mapper",
"memory mapper", MEMORY_MAPPER_SIZE * 1024)
277 , mapperIO(checkedRam ?
std::make_unique<MapperIO>(*this) : nullptr)
282 sdCard[0] = std::make_unique<SdCard>(
DeviceConfig(config, config.findChild(
"sdcard1")));
283 sdCard[1] = std::make_unique<SdCard>(
DeviceConfig(config, config.findChild(
"sdcard2")));
317 for (
auto [i, mr] :
enumerate(memMapperRegs)) {
321 for (
auto [bank, reg] :
enumerate(bankRegsSubSlot3)) {
322 reg = (bank == 1) ? 1 : 0;
330byte MegaFlashRomSCCPlusSD::getSubSlot(
unsigned addr)
const
332 return isSlotExpanderEnabled() ?
333 (subslotReg >> (2 * (addr >> 14))) & 3 : 1;
336void MegaFlashRomSCCPlusSD::writeToFlash(
unsigned addr,
byte value)
338 if (isFlashRomWriteEnabled()) {
339 flash.
write(addr, value);
348 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
350 return subslotReg ^ 0xFF;
353 switch (getSubSlot(addr)) {
354 case 0:
return peekMemSubSlot0(addr);
355 case 1:
return peekMemSubSlot1(addr, time);
356 case 2:
return isMemoryMapperEnabled() ?
357 peekMemSubSlot2(addr) : 0xFF;
358 case 3:
return peekMemSubSlot3(addr, time);
365 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
367 return subslotReg ^ 0xFF;
370 switch (getSubSlot(addr)) {
371 case 0:
return readMemSubSlot0(addr);
372 case 1:
return readMemSubSlot1(addr, time);
373 case 2:
return isMemoryMapperEnabled() ?
374 readMemSubSlot2(addr) : 0xFF;
375 case 3:
return readMemSubSlot3(addr, time);
382 if (isSlotExpanderEnabled() &&
388 switch (getSubSlot(addr)) {
389 case 0:
return getReadCacheLineSubSlot0(addr);
390 case 1:
return getReadCacheLineSubSlot1(addr);
391 case 2:
return isMemoryMapperEnabled() ?
393 case 3:
return getReadCacheLineSubSlot3(addr);
400 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
402 byte diff = value ^ subslotReg;
404 for (
auto i :
xrange(4)) {
405 if (diff & (3 << (2 * i))) {
411 switch (getSubSlot(addr)) {
412 case 0: writeMemSubSlot0(addr, value);
break;
413 case 1: writeMemSubSlot1(addr, value, time);
break;
414 case 2:
if (isMemoryMapperEnabled()) {
415 writeMemSubSlot2(addr, value);
418 case 3: writeMemSubSlot3(addr, value, time);
break;
425 if (isSlotExpanderEnabled() &&
431 switch (getSubSlot(addr)) {
432 case 0:
return getWriteCacheLineSubSlot0(addr);
433 case 1:
return getWriteCacheLineSubSlot1(addr);
434 case 2:
return isMemoryMapperEnabled() ?
436 case 3:
return getWriteCacheLineSubSlot3(addr);
443byte MegaFlashRomSCCPlusSD::readMemSubSlot0(
word addr)
447 return flash.
read(addr & 0x3FFF);
450byte MegaFlashRomSCCPlusSD::peekMemSubSlot0(
word addr)
const
454 return flash.
peek(addr & 0x3FFF);
457const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot0(
word addr)
const
462void MegaFlashRomSCCPlusSD::writeMemSubSlot0(
word addr,
byte value)
465 writeToFlash(addr & 0x3FFF, value);
468byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot0(
word )
475void MegaFlashRomSCCPlusSD::updateConfigReg(
byte value)
477 if ((value ^ configReg) & 0x08) {
479 for (
auto port : {0xa0, 0xa1}) {
483 for (
auto port : {0xa0, 0xa1}) {
493MegaFlashRomSCCPlusSD::SCCEnable MegaFlashRomSCCPlusSD::getSCCEnable()
const
495 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
497 }
else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
504unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot1(
unsigned addr)
const
506 unsigned page = is64KmapperConfigured() ? (addr >> 14) : ((addr >> 13) - 2);
507 unsigned size = is64KmapperConfigured() ? 0x4000 : 0x2000;
509 if (page >= 4)
return unsigned(-1);
511 unsigned bank = bankRegsSubSlot1[page];
512 if (isDSKmodeEnabled() && (page == 0) && (bank == 0)) {
514 }
else if (isDSKmodeEnabled() && (page == 1) && (bank == 1)) {
520 unsigned tmp = (bank *
size) + (addr & (size - 1));
521 return (tmp + 0x010000) & 0x7FFFFF;
524byte MegaFlashRomSCCPlusSD::readMemSubSlot1(
word addr, EmuTime::param time)
526 if (isKonamiSCCmapperConfigured()) {
527 SCCEnable enable = getSCCEnable();
528 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
529 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
530 byte val = scc.
readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
535 unsigned flashAddr = getFlashAddrSubSlot1(addr);
536 return (flashAddr !=
unsigned(-1))
537 ? flash.
read(flashAddr)
541byte MegaFlashRomSCCPlusSD::peekMemSubSlot1(
word addr, EmuTime::param time)
const
543 if (isKonamiSCCmapperConfigured()) {
544 SCCEnable enable = getSCCEnable();
545 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
546 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
547 byte val = scc.
peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
552 unsigned flashAddr = getFlashAddrSubSlot1(addr);
553 return (flashAddr !=
unsigned(-1))
554 ? flash.
peek(flashAddr)
558const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot1(
word addr)
const
560 if (isKonamiSCCmapperConfigured()) {
561 SCCEnable enable = getSCCEnable();
562 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
563 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
568 unsigned flashAddr = getFlashAddrSubSlot1(addr);
569 return (flashAddr !=
unsigned(-1))
574void MegaFlashRomSCCPlusSD::writeMemSubSlot1(
word addr,
byte value, EmuTime::param time)
577 unsigned flashAddr = getFlashAddrSubSlot1(addr);
586 if (!isConfigRegDisabled() && (addr == 0x7FFC)) {
588 updateConfigReg(value);
591 if (!isMapperRegisterDisabled() && (addr == 0x7FFF)) {
597 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
599 offsetReg = (offsetReg & 0x300) | value;
603 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
605 offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
609 if (isKonamiSCCmapperConfigured()) {
611 if ((addr & 0xFFFE) == 0xBFFE) {
614 :
SCC::Mode::Compatible);
618 SCCEnable enable = getSCCEnable();
619 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
620 ((sccMode & 0x10) == 0x10);
621 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
622 if (((enable == EN_SCC) && !isRamSegment2 &&
623 (0x9800 <= addr) && (addr < 0xA000)) ||
624 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
625 (0xB800 <= addr) && (addr < 0xC000))) {
626 scc.
writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
631 unsigned page8kB = (addr >> 13) - 2;
632 if (!areBankRegsAndOffsetRegsDisabled() && (page8kB < 4)) {
634 switch (mapperReg & 0xE0) {
637 if ((addr & 0x1800) == 0x1000) {
641 sccBanks[page8kB] = value;
644 byte mask = areKonamiMapperLimitsEnabled() ? 0x3F : 0xFF;
645 bankRegsSubSlot1[page8kB] = value & mask;
651 if (isWritingKonamiBankRegisterDisabled() && (addr < 0x6000)) {
660 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000)))
break;
661 byte mask = areKonamiMapperLimitsEnabled() ? 0x1F : 0xFF;
662 bankRegsSubSlot1[page8kB] = value & mask;
669 bankRegsSubSlot1[page8kB] = value;
675 if ((0x6000 <= addr) && (addr < 0x8000)) {
676 byte bank = (addr >> 11) & 0x03;
677 bankRegsSubSlot1[bank] = value;
697 const uint16_t mask = (1 << 9) - 1;
698 if ((0x6000 <= addr) && (addr < 0x6800)) {
699 bankRegsSubSlot1[0] = (2 * value + 0) & mask;
700 bankRegsSubSlot1[1] = (2 * value + 1) & mask;
703 if ((0x7000 <= addr) && (addr < 0x7800)) {
704 bankRegsSubSlot1[2] = (2 * value + 0) & mask;
705 bankRegsSubSlot1[3] = (2 * value + 1) & mask;
712 if (flashAddr !=
unsigned(-1)) {
713 writeToFlash(flashAddr, value);
717byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(
word )
724unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(
word address)
const
726 auto bank = memMapperRegs[address >> 14];
727 return ((bank & MEMORY_MAPPER_MASK) << 14) | (address & 0x3FFF);
730byte MegaFlashRomSCCPlusSD::readMemSubSlot2(
word addr)
733 return checkedRam->read(calcMemMapperAddress(addr));
736byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(
word addr)
const
738 return checkedRam->peek(calcMemMapperAddress(addr));
741const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(
word addr)
const
743 return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
746void MegaFlashRomSCCPlusSD::writeMemSubSlot2(
word addr,
byte value)
749 checkedRam->write(calcMemMapperAddress(addr), value);
752byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(
word addr)
754 return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
757byte MegaFlashRomSCCPlusSD::MapperIO::readIO(
word port, EmuTime::param time)
759 return peekIO(port, time);
762byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(
word port, EmuTime::param )
const
764 return getSelectedSegment(port & 3) |
byte(~MEMORY_MAPPER_MASK);
767void MegaFlashRomSCCPlusSD::MapperIO::writeIO(
word port,
byte value, EmuTime::param )
769 mega.memMapperRegs[port & 3] = value & MEMORY_MAPPER_MASK;
770 mega.invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
773byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(
byte page)
const
775 return mega.memMapperRegs[page];
780unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(
unsigned addr)
const
782 unsigned page8kB = (addr >> 13) - 2;
783 return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
786byte MegaFlashRomSCCPlusSD::readMemSubSlot3(
word addr, EmuTime::param )
788 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
790 return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
793 if ((0x4000 <= addr) && (addr < 0xC000)) {
795 unsigned flashAddr = getFlashAddrSubSlot3(addr);
796 return flash.
read(flashAddr);
803byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(
word addr, EmuTime::param )
const
805 if ((0x4000 <= addr) && (addr < 0xC000)) {
807 unsigned flashAddr = getFlashAddrSubSlot3(addr);
808 return flash.
peek(flashAddr);
815const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(
word addr)
const
817 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
821 if ((0x4000 <= addr) && (addr < 0xC000)) {
823 unsigned flashAddr = getFlashAddrSubSlot3(addr);
830void MegaFlashRomSCCPlusSD::writeMemSubSlot3(
word addr,
byte value, EmuTime::param )
833 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
834 if (addr >= 0x5800) {
835 selectedCard = value & 1;
838 sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0);
842 if ((0x4000 <= addr) && (addr < 0xC000)) {
843 unsigned flashAddr = getFlashAddrSubSlot3(addr);
844 writeToFlash(flashAddr, value);
848 if ((0x6000 <= addr) && (addr < 0x8000)) {
849 byte page8kB = (addr >> 11) & 0x03;
850 bankRegsSubSlot3[page8kB] = value;
856byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(
word )
865 switch (port & 0xFF) {
867 if (!isPSGalsoMappedToNormalPorts())
return;
870 psgLatch = value & 0x0F;
874 if (!isPSGalsoMappedToNormalPorts())
return;
885template<
typename Archive>
889 ar.template serializeBase<MSXDevice>(*
this);
892 ar.serialize(
"flash", flash,
893 "subslotReg", subslotReg);
899 ar.serialize(
"scc", scc,
901 "sccBanks", sccBanks,
903 "psgLatch", psgLatch,
904 "configReg", configReg,
905 "mapperReg", mapperReg,
906 "offsetReg", offsetReg,
907 "bankRegsSubSlot1", bankRegsSubSlot1);
908 if constexpr (Archive::IS_LOADER) {
910 byte tmp = configReg;
912 updateConfigReg(tmp);
917 if (checkedRam) ar.serialize(
"ram", checkedRam->getUncheckedRam());
918 ar.serialize(
"memMapperRegs", memMapperRegs);
921 ar.serialize(
"bankRegsSubSlot3", bankRegsSubSlot3,
922 "selectedCard", selectedCard,
923 "sdCard0", *sdCard[0],
924 "sdCard1", *sdCard[1]);
#define REGISTER_MSXDEVICE(CLASS, NAME)
void reset(EmuTime::param time)
void writeRegister(unsigned reg, uint8_t value, EmuTime::param time)
void write(size_t address, uint8_t value)
const uint8_t * getReadCacheLine(size_t address) const
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
uint8_t read(size_t address)
uint8_t peek(size_t address) const
static DummyAY8910Periphery & instance()
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void unregister_IO_Out_range(byte port, unsigned num, MSXDevice *device)
void register_IO_Out_range(byte port, unsigned num, MSXDevice *device)
void unregister_IO_Out(byte port, MSXDevice *device)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
static std::array< byte, 0x10000 > unmappedRead
static std::array< byte, 0x10000 > unmappedWrite
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
EmuTime::param getCurrentTime() const
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.
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.
~MegaFlashRomSCCPlusSD() override
void setMode(Mode newMode)
void powerUp(EmuTime::param time)
uint8_t readMem(uint8_t address, EmuTime::param time)
void reset(EmuTime::param time)
uint8_t peekMem(uint8_t address, EmuTime::param time) const
void writeMem(uint8_t address, uint8_t value, EmuTime::param time)
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer
uint16_t word
16 bit unsigned integer
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)